나는 bash 매뉴얼을 읽고 있었는데 다음과 같은 섹션을 보았습니다.
"명령 대체, 괄호로 묶인 명령 및 비동기 명령은 쉘 환경과 중복되는 서브쉘 환경에서 호출됩니다."
제 질문은 서브쉘에서 무엇이 실행되고 있는지 실제로 볼 수 있는 방법이 있느냐는 것입니다. 예를 들어, 내가 다음 줄을 쓴다고 가정해보자. 서브셸에서 실행되는 내용을 실제로 보려면 어떻게 해야 합니까?
$ printf "first\nsecond\nthird" | grep -E "(first|second)"
서브셸에서 실제로 실행되는 내용을 어떻게 확인할 수 있습니까? 두 번째 셸에서 "첫 번째"를 파악한 다음 "두 번째"를 파악하는 것으로 의심되지만, 이것이 무엇을 하고 있는지 보고 싶습니다.
답변1
직접적으로 볼 수는 없을 것 같아요.
xtrace
( set -x
)는 s 및 명령 대체의 중첩 수준을 표시 eval
하지만 괄호 안의 그룹은 표시하지 않습니다.
Bash는 하위 프로세스에서 하위 쉘을 실행하므로 원칙적으로할 수 있다Linux에서 syscall 셸과 해당 하위 프로세스 를 실행 strace
하거나 유사하게 보려고 시도했지만 출력을 해석하기가 약간 어렵습니다. 또한 이와 같은 내장 기능은 호출 에 표시되지 않으며 Bash 프로세스는 실행할 명령이 하나만 있는 경우 한 수준의 분기를 건너뜁니다. 예를 들어, 외부 명령이 분기되지 않으며 마찬가지로 하위 쉘과 외부 명령이 두 개 포크되는 대신 하위 쉘 포크가 하나만 있습니다.fork()
clone()
execve()
printf
execve()
bash -c '/bin/false'
(/bin/false)
$BASHPID
다른 장소 에서 인쇄 하여 $$
. 실행된 명령이 표시되지는 않지만 이러한 인쇄물을 펼치면 약간 혼란스럽습니다.$BASHPID
$$
$ echo $$ >&2; { echo "lhs: $BASHPID" >&2; printf foobar; } | { echo "rhs: $BASHPID" >&2; grep oo; }
30163
rhs: 30166
lhs: 30165
foobar
예, 인용한 섹션에서는 언급되지 않았지만 파이프라인의 두 부분이 모두 서브셸에서 실행되고 있음을 출력에서 알 수 있습니다.
어쨌든 서브셸에서 실행되는 주요 항목은 인용문에서 언급한 세 가지와 파이프입니다.
비동기/백그라운드 프로세스는 명백합니다. 셸과 동시에 실행되므로 동일한 프로세스에 있을 수 없습니다. 파이프라인의 다양한 부분도 동시에 실행되어야 하므로 최대 기본 셸 프로세스에서 실행될 수 있습니다. (Bash에서는 옵션이 설정되고 유효한 경우 가장 오른쪽 부분이 이 작업을 수행하고, lastpipe
그렇지 않으면 둘 다 자체 하위 쉘/프로세스를 갖습니다.)
괄호로 묶인 그룹은 명시적으로 서브쉘의 사용을 요구하며, 명령 대체에 대한 변명이 생각나지 않으므로 그들이 그렇게 한다는 점을 받아들여야 할 것 같습니다.
서브셸의 변경 사항은 기본 셸에 전파되지 않으므로 테스트가 비교적 간단합니다. 예를 들어 다음을 실행하는 경우:
bash -c 's=
s+=direct.
(s+=parens.)
$(s+=comsub.)
s+=pipeleft. | s+=piperight.
s+=async. &
eval s+=eval.
echo $s'
당신은 출력을 얻었 direct.eval.
으므로 이것은 다음과 같습니다아니요서브셸에서 실행합니다. 나머지는 완료되었습니다. -O lastpipe
이전에 추가했거나 스크립트 내에서 추가한 경우 목록에도 추가된 것을 볼 수 -c
있습니다 .shopt -s lastpipe;
piperight
답변2
grep
첫째, exec가 두 하위 쉘 모두에 있는지 확실하지 않습니다 .
그러나 명령을 실행할 때 어떤 일이 발생하는지 확인하려면 command 를 사용할 수 있습니다 truss
. 그것은 다음과 같습니다:
printf "first\nsecond\nthird" | truss -o out.log grep -E "(first|second)"
out.log
시스템 호출 및 신호와 같은 명령 에 저장됩니다 .
여기있어매뉴얼 페이지나중에 참고할 수 있도록 truss
.
strace
나는 당신이 명령에서 그것을 바꿀 수 있다고 생각합니다 :
printf "first\nsecond\nthird" | strace -o out.log grep -E "(first|second)"
그러나 주의하시기 바랍니다truss
전체 쉘, 서브쉘 생성, 시스템 호출 등을 추적하려면 다음 형식의 명령을 사용해야 합니다.
strace -o out.log 'printf "first\nsecond\nthird" | grep -E "(first|second)"'