external_command {var}>somefile을 사용할 때 bash가 var에 fd를 할당하지 않는 이유는 무엇입니까?

external_command {var}>somefile을 사용할 때 bash가 var에 fd를 할당하지 않는 이유는 무엇입니까?

bash 맨페이지에 따르면 "리디렉션 연산자는 간단한 명령 앞이나 명령 내의 어느 위치에나 나타날 수 있거나 명령 뒤에 나타날 수 있습니다."

또한 매뉴얼 페이지에 따르면 "간단한 명령은 일련의 선택적 변수 할당, 공백으로 구분된 단어 및 리디렉션이 뒤따르고 제어 연산자에 의해 종료되는 것입니다."

이제 질문이 생깁니다. 간단한 명령과 쉘이 의미하는 명령은 무엇입니까? 왜냐하면 /bin/echo foo {var}> somefilevar에는 fd가 할당되지 않았기 때문입니다. 대조적으로 이로 echo foo {var}> somefile인해 fd가 var에 할당됩니다. 명령어와는 다르게 내장된 명령어로 동작하는 것 같습니다. 나는 이 구조가 내장 명령이 사용되는 어느 곳에서나 나타날 수 있다는 것을 알았습니다 {var}> someFile echo foo. 이런 경우, 간단한 명령어가 내장 명령어로 구성되어 있다면, 단어나 토큰도 내장 명령어인가요? 매뉴얼 페이지에 다음과 같이 나와 있기 때문입니다. "Word: 셸에서 단일 단위로 처리되는 일련의 문자입니다. 토큰이라고도 합니다."

또한 외부 명령 대신 내장 명령과 함께 사용할 때 fd가 할당되는 것을 관찰했습니다. 그렇다면 여기서 문제는 무엇입니까? 내 관찰이 정확합니까? 단순 명령과 명령의 차이점은 무엇입니까? 맨페이지는 이에 대해 매우 모호합니다.

답변1

내 머리 꼭대기에서 이것은 외부 명령을 실행할 때 쉘이 1) 포크, 2) 하위 프로세스의 리디렉션을 처리하고 3) exec가 실제 명령이기 때문이라고 추측합니다. 2에서 할당이 완료되면 var하위 프로세스에서 시작된 프로그램이 종료된 후 상위 쉘에 표시되지 않습니다. 내장 기능을 사용하면 포크가 없으며 쉘은 기본 쉘 프로세스에서 필요에 따라 fd를 처리하고 거기에서 변수 할당이 적용됩니다.

어쨌든 리디렉션은 some external command {var}>/whatever쓸모가 없으므로 중요하지 않습니다. 외부 명령은 어떤 fd가 열려 있는지 알 수 없으며 어떤 fd가 있는지 확인할 수 있지만 이 줄의 리디렉션을 위해 열린 것 외에 다른 fd가 있을 수 있으므로 해당 fd를 안정적으로 사용할 수 없습니다. 로 출력합니다 /whatever. 대신 일반적으로 고정된 fd 번호를 사용하거나 일부 명령줄 인수 또는 환경 변수를 사용하여 사용할 fd 번호를 알려줍니다.

하지만 여기서도 그렇게 할 수 없습니다. 명령줄에서 확장을 처리할 때 변수가 설정되지 않아 실행된 프로그램에 전달하기 어렵기 때문입니다. unset var; /bin/echo "var=$var" {var}>/dev/null출력은 바로 그것 var=입니다 unset var; var=$var /usr/bin/env {var}>/dev/null |grep ^var. (ksh와 zsh에서는 후자는 환경을 통해 실제 숫자를 전달하는 것 같습니다.)

이 리디렉션이 의미가 있는 유일한 곳은 exec {var}>/whatever내장 변수로서 변수가 기본 셸에 설정되고 값이 다음 명령에 사용 가능한 경우입니다.

답변2

GNU bash 문서 섹션 3.6단락 2에는 "리디렉션할 때마다..."라고 나와 있습니다.

fd 와 같은 명령에서 fd 가 실제로 사용되는지 여부에 관계없이 cmd {fd}>file모든 내장 명령은 fd를 설정하는 것처럼 보이고 외부 명령은 fd를 설정하지 않는 것 같습니다. bash 또는 가이드가 잘못되었습니다.

Paul--) echo "Hello, Worms" {var}>real 1>&${var}
Paul--) declare -p var; ls -l real; cat real
declare -- var="11"
-rw-r--r-- 1 paul paul 13 Sep  2 10:27 real
Hello, Worms
Paul--) 
Paul--) /bin/echo "So long, suckers" {why}>deal 1>&${why}
Paul--) declare -p why; ls -l deal; cat deal
bash: declare: why: not found
-rw-r--r-- 1 paul paul 17 Sep  2 10:29 deal
So long, suckers
Paul--) 

실제로 $why 값은 두 번째 리디렉션(stdout)에서 사용할 수 있지만 가이드에 지정된 것과는 다릅니다. "{varname}이 제공되면 리디렉션이 지속됩니다.명령의 범위를 넘어서...".

이 할당의 유일한 이점은 인코더가 숫자를 추적해야 하는 대신 이름으로 사용 가능한 fd를 할당한다는 것입니다.

: 9>myFirstFile
cmd >&9

: {fdLog}>myLogFile
cmd >&${fdLog}

관련 정보