다음 명령을 고려하십시오.
exit > /dev/null
exit | cat
일부 셸(ksh, bash, (d)ash)에서는 동작이 동일합니다. 첫 번째 명령을 실행하면 셸이 즉시 종료되지만 두 번째 명령에는 눈에 띄는 동작이 없습니다.
exit
나는 첫 번째 명령이 fork(2)를 포함하지 않는 반면, 두 번째 명령은 두 개(하나는 exec용 , 다른 하나는 execve(2)용 ) 와 관련이 있다는 결론에 도달했습니다 cat
.
POSIX 사양의 섹션 2.14를 살펴봤지만 이를 명시적으로 설명하는 항목을 찾지 못했습니다.
POSIX에서는 일부 명령은 fork(2)를 수행하면 안 되지만 다른 명령은 반드시 수행해야 한다고 지정합니까? 첫 번째 명령에 대해 하위 쉘을 생성하는 것이 표준에 따라 허용됩니까?
( exit )
대괄호는 exit
실제로 명령을 실행하는 하위 쉘 을 생성하므로 현재 쉘을 종료해서는 안 된다는 것을 알고 있습니다. 즉, 하위 쉘이 즉시 종료된다는 의미입니다. 그러나 여기에는 대괄호가 없기 때문에 리디렉션과 파이프에 대해 잘 모르겠습니다.
제가 이 질문을 하는 이유는 최근 강좌 실습에서 최소한의 Unix 셸을 구현하라는 지시를 받았기 때문입니다. 이를 보완하기 위해 구현할 수 있는 "선택적 기능"이 많이 있습니다. 이러한 "선택적 기능" 중 하나는 리디렉션과 파이프가 결합된 것입니다. 우리는 몇 가지 다른 구현을 가지고 있으며 그 중 일부는 다른 것보다 POSIX의 지정된 동작에 더 가깝다고 생각하므로 실제 동작이 어떻게 지정되는지 알고 싶습니다.
답변1
훌륭한(출구),
이것출구유틸리티는 셸을 활성화해야 합니다.그만두다 현재 실행 환경[...]
그리고(2.12. 쉘 실행 환경)
서브쉘 환경은 쉘 환경의 복사본으로 생성되어야 합니다. [...] 추가적으로,각 명령에 대해 서브셸 환경에 위치한 다중 명령 파이프라인; 그러나 확장을 통해 파이프라인의 일부 또는 모든 명령을 현재 환경에서 실행할 수 있습니다.다른 모든 명령은 현재 쉘 환경.
따라서 exit
파이프라인에 있는 내용은 자체 실행 환경/하위 셸에서 실행되고 종료되는 반면, 간단한 명령에 있는 내용은 exit > /dev/null
기본 셸 환경에서 실행됩니다. (댓글에서 지적했듯이 리디렉션은 실제로 전혀 영향을 미치지 않습니다.)
두 번째 따옴표 사이의 부분은 일부 쉘이 기본 환경에 파이프된 모든 명령을 실행할 수 있음을 의미하므로 이 경우에도 전체 쉘이 종료됩니다. 실제로는 파이프라인의 마지막 명령에 대해 이 작업을 수행하는 것이 더 일반적입니다.
예를 들어 Bash에서는 lastpipe
다음과 같습니다.
$ bash -c 'true | exit; echo end.'
end.
하지만
$ bash -O lastpipe -c 'true | exit; echo end.'
아무것도 인쇄되지 않습니다.
답변2
이는 exit
for의 하위 쉘이 아닌 for에서 실행되기 때문에 발생합니다. exit | cat
exit > /dev/null
서브쉘을 종료해도 메인 쉘이 종료되지 않습니다.:
현재 실행 환경이 서브쉘 환경인 경우 쉘은 지정된 종료 상태로 서브쉘 환경을 종료하고 서브쉘 환경을 호출한 환경에서 계속 실행됩니다.
그러나 서브쉘과 서브쉘이 아닌 것의 구체적인 차이점은 이 장에서 자세히 설명됩니다.POSIX 표준 2.12– 관련 구절 전체를 인용하십시오.
서브쉘 환경은 쉘 환경의 복사본으로 생성되어야 하지만 무시되지 않는 신호 트랩은 기본 동작으로 설정되어야 합니다. 서브쉘 환경에 대한 변경사항은 쉘 환경에 영향을 주어서는 안됩니다. 명령 대체, 괄호로 그룹화된 명령 및 비동기 목록은 서브쉘 환경에서 실행되어야 합니다. 또한 다중 명령 파이프라인의 각 명령은 하위 셸 환경에 있지만 확장으로 파이프라인의 일부 또는 모든 명령을 현재 환경에서 실행할 수 있습니다. 다른 모든 명령은 현재 쉘 환경 내에서 실행되어야 합니다.
이는 exit | cat
설명에 적합합니다.
다중 명령 파이프라인의 각 명령은 서브셸 환경에 위치합니다.
그러므로 그것은대개서브쉘에서 실행됩니다. 그러나 이로 인해 문제가 발생할 수 있습니다.
그러나 확장을 통해 파이프라인의 일부 또는 모든 명령을 현재 환경에서 실행할 수 있습니다.
...이는 모든 쉘에서 이것이 보장되지는 않는다는 것을 의미합니다. 이전에는 하나의 구현이 현재 셸에서 파이프의 오른쪽을 실행하여 다음 코드가 KSH의 일부 구현에서는 작동하지만 다른 구현에서는 작동하지 않는 코드를 디버깅해야 했습니다.
cat foo | while read line
do
X="$line"
done
그러니 항상 파이프를 가정하세요가능한서브쉘을 생성하되 이에 의존하지 마십시오.