운영 체제FreeBSD-12.2
제가 사용하는 가상 프린터 설정이 있습니다 socat
. 이 socat
명령은 백그라운드에서 실행됩니다. 입력 스트림을 처리하고 이를 전송하여 gpcl6
PDF 문서를 생성하는 시스템 셸을 생성합니다. 출력은 특정 디렉터리의 파일로 이동됩니다. 파일 이름에는 타임스탬프가 포함되어야 합니다 $(date -Iseconds)
. 문제는 이 타임스탬프가 socat
명령이 시작된 후에만 계산되고 이후에는 계산되지 않는다는 것입니다. 내 질문은: 데이터 스트림이 도착할 때마다 재평가하는 방법이 있습니까?
완전한 명령은 다음과 같습니다:
HPNP=4178 socat TCP4-LISTEN:4178,bind=192.168.216.179,fork,reuseaddr,su=hp3000 시스템: "sed -r '1s/^.{42}//' | cat /var/spool/hp3000/forms /hll_inv_ljiiii_85.ovl - | gpcl6 -dNOSAFE -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=/var/spool/hp3000/np4178/HP3000-INV-"$(date -Iseconds)"-%03u.pdf -" &
작은 따옴표, 큰 따옴표 및 따옴표 없음을 시도했습니다. 명령은 세 가지 옵션 모두로 시작됩니다. 그러나 작은따옴표와 큰따옴표는 동일한 결과를 생성하며 타임스탬프는 명령이 시작된 시간으로 고정됩니다. 따옴표가 없으면 명령이 시작되지만 명령에 전송된 모든 항목은 지속적으로 파이프 파손 오류를 발생시킵니다.
2021/05/17 15:56:55 socat[17557] E write(5, 0x800b09000, 1460): Broken pipe
cat: stdout: Broken pipe
sed: stdout: Broken pipe
socat 매뉴얼 페이지에는 다음이 있습니다.
SYSTEM:<shell-command>
Forks a sub process that establishes communication with its
parent process and invokes the specified program with system() .
Please note that <shell-command> [string] must not contain ','
or "!!", and that shell meta characters may have to be
protected. After successful program start, socat writes data to
stdin of the process and reads from its stdout.
Option groups: FD,SOCKET,EXEC,FORK,TERMIOS
Useful options: path, fdin, fdout, chroot, su, su-d, nofork,
pty, stderr, ctty, setsid, pipes, sigint, sigquit
See also: EXEC
내가 아는 한, 쉘은 포크되지만 시작 시 한 번만 발생합니다. 이것이 데이터 스트림이 도착할 때마다 $() 구성이 평가되지 않는 이유입니까? 어쨌든, 이것에도 한계가 있나요?
답변1
따옴표는 $(date)
명령에 영향을 주지 않으므로 항상 socat
명령을 실행하기 직전에 평가됩니다.
$(date)
설명 목적으로 명령을 단순화하기 위해 따옴표를 사용하지 않는 방법을 보여주는 약간 더 간단한 보기가 되기를 바랍니다.
socat TCP4-LISTEN:flags SYSTEM:"sed | gpcl6 file-"$(date)"-suffix"
# ^in quotes ^out ^in ^out
큰따옴표 안에 넣으면 지금과 같이 평가됩니다(단, 결과 출력의 공백은 단어 구분점이 아닌 공백으로 유지됩니다). 작은따옴표 안에 넣으면 socat
옵션을 평가하기 위해 호출된 셸이 SYSTEM
모든 호출에서 옵션을 평가합니다.
socat TCP4-LISTEN:flags SYSTEM:'sed | gpcl6 file-$(date)-suffix'
두 개의 서로 다른 시스템에서 실행되는 이 명령 쌍을 사용하여 이를 실제로 확인할 수 있습니다.
# Server
socat TCP4-LISTEN:4178,fork,reuseaddr SYSTEM:'cat >socat.$(date +%H%M%S).txt'
# Client
echo boo | nc remoteServer 4178
# Sever
ls șocat.*.txt
이 변경 사항을 원래 코드에 다시 적용하면 다음과 같은 결과를 얻게 됩니다(편의를 위해 명령에서 사용되는 따옴표 유형도 바꿨습니다 sed
).
HPNP=4178 socat TCP4-LISTEN:4178,bind=192.168.216.179,fork,reuseaddr,su=hp3000 SYSTEM:'sed -r "1s/^.{42}//" | cat /var/spool/hp3000/forms/hll_inv_ljiii_85.ovl - | gpcl6 -dNOSAFE -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=/var/spool/hp3000/np4178/HP3000-INV-$(date -Iseconds)-%03u.pdf -' &