Bash 4.4.19(1) - 출시됨
아래에는 로깅 애플리케이션의 기초가 되는 간단한 스크립트가 있습니다. 여러 가지 이유로 프로세스 대체를 사용해야 했습니다.
이것이 runner
애플리케이션의 핵심이며, 프로세스 교체가 비동기식이므로 루프를 사용하여 일관성을 유지하는 데 성공했습니다 while
. 완벽하게 작동합니다.
bash <filename> <function>
불행히도 작동하지 않는 상황을 발견했습니다. ' '를 실행할 때
따라서 재생산하려면 2개의 파일이 필요합니다.
필요하다:
- 왜 이런 일이 발생합니까?
- 유사한 상황을 수용하기 위해 while 루프를 어떻게 수정할 수 있습니까?
단순화된 스크립트는 다음과 같습니다.
test.sh
#!/bin/bash
2sub() {
local in=$(cat); echo -e "$in";
}
runner () {
"${@}" 1> >(2sub)
while [ -e /proc/$! ]; do sleep 0.1; done # <<< LOOP WAIT FOR $!
}
remotesub() {
bash ./test2.sh remotesub2
}
echo -e "running\n";
runner bash ./test2.sh remotesub2 # LOOPS
# runner remotesub # A POSSIBLE BYPASS/SOLUTION? But why?
echo -e "done!\n"
test2.sh
remotesub2() {
echo -e "'${BASH_VERSION}'"
return 0
}
"$@"
우회로:
bash <filename> <function>
스크립트에서 볼 수 있듯이 문제를 함수 안에 래핑하여 문제를 우회할 수 있습니다.전달 함수to runner
. 이것이 직접적인 방법 대신에 작동하는 이유는 여기 누군가가 알고 있다고 확신합니다.
이 문제를 해결하고 이러한 경우를 처리하기 위해 대기 루프를 수행하는 더 좋은 방법이 있는지 알려주세요.
해결책:
가장 좋은 솔루션은 mosvy가 제안한 솔루션입니다. 감사해요. 를 사용하면 { "${@}"; }
명령을 별도의 작은 기능으로 래핑할 필요가 없어져 고통스러울 수 있습니다. 또한 더 큰 코드로 여러 시간 동안 테스트한 후 하위 프로세스를 신중하게 종료하면 이 작업이 불필요하다는 결론을 내렸습니다 while [ -e /proc/$! ]; do sleep 0.1; done
. 라인은 다음으로 대체됩니다.wait $!;
답변1
제가 정확히 이해한다면, 왜 $!
내부에서 실행되는 프로세스의 PID가 내장 명령이나 함수의 명령줄의 일부일 때만 설정되고 >(...)
, 내장 명령줄의 일부일 때는 설정되지 않는지 궁금하실 것입니다. 명령 또는 기능의 일부는 외부 명령입니다.
단순화된 예:
$ bash -c 'true > >(echo in=$BASHPID; sleep .1); echo psubst=$!'
psubst=12392
in=12392
$ bash -c '/bin/true > >(echo in=$BASHPID; sleep .1); echo psubst=$!'
in=12751
psubst=
이는 외부 명령을 사용하는 경우 bash
이를 실행하기 위해 별도의 프로세스가 분기되고 해당 프로세스에서 실행 중인 프로세스가 >(...)
해당 프로세스의 하위로 실행되기 때문에 발생합니다.멋진완전히 통제할 수 없는 스크립트의 하위 항목입니다.
외부 명령이 종료되면 해당 하위 명령(아직 실행 중인 경우)이 pid 1(init)에 의해 채택되므로 스크립트에서 해당 PID를 검색하는 데 여전히 사용할 수 있는 모든 링크가 끊어집니다.
해결 방법은 명령줄의 모든 프로세스 교체가 스크립트의 하위 프로세스로 실행되어 를 통해 전달되도록 하는 래퍼 함수를 사용하는 것입니다 pgrep -P "$$"
.
또한 외부 명령을 {...}
블록에 넣고 블록의 출력을 리디렉션하는 것이 작동하는 것 같습니다.
$ bash -c 'func(){ /bin/true; }; func > >(echo in=$BASHPID; sleep .1); echo psubst=$!'
in=3574
psubst=3574
$ bash -c '{ /bin/true; } > >(echo in=$BASHPID; sleep .1); echo psubst=$!'
in=3435
psubst=3435
두 해결 방법 모두 현재 구현의 작동 방식에 따라 다릅니다. bash
언젠가는 사소한 그룹 명령이나 기능을 최적화하고 이러한 가정을 깨기로 결정할 수도 있습니다.
PID를 마지막 프로세스 교체로 설정하는 것은 $!
NET에서 사용할 수 없는 문서화되지 않은 기능입니다 bash
.