답변:
3>&4-
는 bash에서 지원하는 ksh93 확장이며 3>&4 4>&-
, 짧습니다 . 즉 3은 이제 4가 사용되었던 위치를 가리키고 4는 이제 닫혀 있으므로 4가 가리키는 것은 이제 3으로 이동했습니다.
일반적인 사용법은 다음과 같이 복제 stdin
하거나 stdout
사본을 저장하고 복원하려는 경우에 사용됩니다.
변수에 stdout을 그대로두고 명령의 stderr (및 stderr 만)을 캡처한다고 가정하십시오.
명령 대체 var=$(cmd)
, 파이프를 작성합니다. 파이프의 쓰기 끝은 cmd
표준 stdout (파일 설명자 1)이되고 다른 끝은 변수를 채우기 위해 셸에서 읽습니다.
이제 stderr
변수로 가려면 다음을 수행하십시오 var=$(cmd 2>&1)
.. 이제 fd 1 (stdout)과 2 (stderr)는 파이프 (그리고 결국 변수)로갑니다. 우리가 원하는 것의 절반에 불과합니다.
우리가 var=$(cmd 2>&1-)
(짧게 var=$(cmd 2>&1 >&-
)하면 이제 cmd
stderr 만 파이프로 이동하지만 fd 1은 닫힙니다. 경우 cmd
시도가 함께 반환 모든 출력, 작성 EBADF
오류가 파일을 열 경우, 그것은 최초의 무료 FD를 얻을 것이다 열려있는 파일에 할당됩니다 stdout
그에 대해 명령 가드하지 않는 한! 우리가 원하는 것도 아닙니다.
stdout을 cmd
단독으로 남겨 두 려면 (즉 , 명령 대체 외부에서 가리키는 동일한 자원을 가리 키려면) 해당 자원을 명령 대체 내부로 가져와야합니다. 이를 위해 명령 대체 stdout
외부 의 사본 을 수행하여 내부로 가져갈 수 있습니다.
{
var=$(cmd)
} 3>&1
더 확실한 작성 방법입니다.
exec 3>&1
var=$(cmd)
exec 3>&-
(또한 결국 fd 3을 닫는 대신 복원하는 이점이 있습니다).
그런 다음 {
(또는 exec 3>&1
) 및을 (를) 기준으로 }
fd 1 및 3 모두 처음에 가리키는 동일한 리소스 fd 1을 가리 킵니다. fd 3은 명령 대체 내의 해당 자원을 가리 킵니다 (명령 대체는 fd 1, stdout 만 경로 재지 정함). 따라서 위의 cmd
fds 1, 2, 3을 얻었습니다.
우리가 그것을 변경하면 :
{
var=$(cmd 2>&1 >&3)
} 3>&1-
그러면 다음과 같이됩니다.
이제 우리는 원하는 것을 얻었습니다. stderr는 파이프로 가고 stdout은 그대로 남아 있습니다. 그러나 우리는 fd 3을cmd
있습니다.
일반적으로 명령은 fds 0 ~ 2가 열려 있고 표준 입력, 출력 및 오류 인 것으로 가정하지만 다른 fd는 가정하지 않습니다. 그들은 아마도 그 fd 3을 그대로 남겨 둘 것입니다. 다른 파일 설명자가 필요한 경우 open()/dup()/socket()...
사용 가능한 첫 번째 파일 설명자를 반환하는 작업을 수행합니다 . 그렇다면 (쉘 스크립트처럼 exec 3>&1
) 그것들을 사용해야합니다.fd
구체적 , 우선 그것을 무언가에 할당 할 것입니다.
fd 3 cmd
을 사용하지 않기 때문에 fd 3을 닫는 것이 좋습니다 . 그러나 전화하기 전에 할당 된 상태로두면 별 문제가되지 않습니다 cmd
. 문제 cmd
(및 잠재적으로 발생하는 다른 프로세스)에 사용 가능한 fd가 하나 더 적을 수 있습니다. 잠재적으로 더 심각한 문제는 fd가 가리키는 리소스가 cmd
백그라운드에서 생성 된 프로세스에 의해 유지 될 수있는 경우 입니다. 해당 리소스가 파이프 또는 다른 프로세스 간 통신 채널 인 경우 (예 : 스크립트가로 실행되는 경우 script_output=$(your-script)
), 다른 쪽 끝에서 읽은 프로세스는 파일 끝까지 파일 끝을 볼 수 없기 때문에 문제가 될 수 있습니다. 백그라운드 프로세스가 종료됩니다.
따라서 여기에 작성하는 것이 좋습니다.
{
var=$(cmd 2>&1 >&3 3>&-)
} 3>&1
다음과 bash
같이 단축 할 수 있습니다.
{
var=$(cmd 2>&1 >&3-)
} 3>&1
거의 사용되지 않는 이유를 요약하면 다음과 같습니다.
>&3
대신에 수행 합니다 .>&3-
>&3 3>&-
거의 사용되지 않는다는 증거 는 bash에서 가짜 임을 알 수 있습니다. bash에서 compound-command 3>&4-
또는 any-builtin 3>&4-
fd 4 후에도 compound-command
또는 any-builtin
반환 된 후에도 닫힙니다 . 이 문제를 해결하기 위한 패치 가 제공됩니다 (2013-02-19).
{ var=$(cmd 2>&1 >&3) ; } 3>&1-
1을 닫는 데 오타가 아닙니까?
$(...)
{...}
가리킨 사용 1가 fd 것과 3 점을 FD로 함과 동시에 1 입력에이어서, 폐쇄가 fd $(...)
1은 그 피드 파이프로 설정된다가 fd $var
후 대한 cmd
것과 2뿐만 아니라, 다음 (1) 어떻게 3 점 1이 닫힌 상태로 남아 있다는 사실은 bash의 버그이므로보고하겠습니다. 해당 기능의 출처 인 ksh93에는 해당 버그가 없습니다.
다른 파일 디스크립터와 동일한 위치를 가리 키도록하는 것을 의미합니다. 당신은 (떨어져 표준 오류 기술자의 명백한 별도의 처리에서 매우 드물게이 작업을 수행하지 필요 stderr
, fd 2
,/dev/stderr -> /proc/self/fd/2
). 복잡한 경우에 유용 할 수 있습니다.
고급 Bash 스크립팅 안내서에는 더 긴 로그 레벨 예제 와이 스 니펫이 있습니다.
# Redirecting only stderr to a pipe.
exec 3>&1 # Save current "value" of stdout.
ls -l 2>&1 >&3 3>&- | grep bad 3>&- # Close fd 3 for 'grep' (but not 'ls').
# ^^^^ ^^^^
exec 3>&- # Now close it for the remainder of the script.
Source Mage 's Sorcery에서 예를 들어 동일한 코드 블록에서 다른 출력을 식별하는 데 사용합니다.
(
# everything is set, so run the actual build infrastructure
run_build
) 3> >(tee -a $C_LOG >> /dev/stdout) \
2> >(tee -a $C_LOG 1>&2 > $VOYEUR_STDERR) \
> >(tee -a $C_LOG > $VOYEUR_STDOUT)
로깅 이유 때문에 추가 프로세스 대체가 추가되었지만 (VOYEUR는 데이터를 화면에 표시할지 아니면 로그 만 표시할지 결정) 일부 메시지는 항상 표시 해야합니다 . 이를 위해 파일 디스크립터 3에 인쇄 한 다음 특수하게 처리합니다.
Unix에서 파일은 파일 디스크립터에 의해 처리됩니다 (예 : 작은 정수, 예를 들어 표준 입력은 0, 표준 출력은 1, 표준 오류는 2입니다. 다른 파일을 열면 일반적으로 사용되지 않는 가장 작은 디스크립터가 지정됩니다). 이 프로그램의 inards을 알고, 당신은 표준 출력에 파일 기술자 (5)로 이동 출력을 보낼 그렇다면, 당신은이 있다고 1. 기술자 5를 이동 줄 2> errors
에서 유래 및 구조물이 좋아 2>&1
에 오류를 복제 출력 스트림
그래서 거의 사용하지 않았지만 (25 년 이상 유일하게 독점적으로 유닉스를 사용했을 때 분노에 한두 번 사용한 것을 막연히 기억합니다), 절대적으로 필요할 때.
5>&1
1 어디로 5를 전송 한 후 정확히 않습니다 1>&5-
(5)를 폐쇄 외에합니까?