>&- 유닉스/리눅스 터미널에서는 무엇을 해야 하나요?

>&- 유닉스/리눅스 터미널에서는 무엇을 해야 하나요?

나는 Unix 명령줄에 대해 잘 모릅니다. 내가 찾은이 답변표준 출력으로 출력하지 않고 명령을 사용하려면 tee다음과 같이 "표준 출력 끄기"를 전달하십시오 >&-.

echo 'hello world' | tee aa bb cc >&-

많이 연구해서 알아냈어요다른 게시물연산자 기능에 대해 문의하세요. 불행히도 자세한 답변을 찾을 수 없습니다.

내가 아는 것은 폐쇄되었다는 것 stdout뿐이지만 그것이 정확히 무엇을 의미하는지, 왜 누군가가 그렇게 하려고 하는지는 알 수 없습니다. 이것이 유용할 수 있는 다른 시나리오가 무엇인지 알고 싶습니다.

해당 연산자의 내부 작업에 대해 자세히 알아볼 수 있는 리소스가 있습니까?

답변1

인용하다sh언어에 대한 POSIX 사양:

2.7.6 출력 파일 설명자 복사

리디렉션 연산자:

[n]>&word

출력 파일 설명자는 다른 출력 파일 설명자에서 복사되어야 합니다.아니면 하나 닫을게. word가 하나 이상의 숫자로 평가되면 n 또는 표준 출력(n이 지정되지 않은 경우)으로 표시되는 파일 설명자는 word의 숫자가 For를 사용하여 열린 파일을 나타내지 않으면 word로 표시되는 파일 설명자의 복사본이 됩니다. 출력 파일 설명자에서 리디렉션 오류가 발생합니다. 셸 오류의 결과를 참조하세요.단어가 "-"로 평가되면 파일 설명자 n 또는 표준 출력(n이 지정되지 않은 경우)이 닫힙니다. 열리지 않은 파일 설명자를 닫으려고 시도하는 것은 오류로 간주되어서는 안 됩니다.단어가 다른 것으로 평가되면 동작이 지정되지 않습니다.

(강조).

stdout의 파일 디스크립터인 1의 약어 도 마찬가지 >&-입니다 .1>&-

그래서:

cmd >&-

쉘은 close(1)나중에 실행되는 프로세스에서 이 작업을 수행합니다 cmd. 따라서 cmdfd 0과 2는 부팅 시 열릴 것입니다(각각 stdin 및 stderr이므로 stdout은 일반적으로 관례에 따라 명령이 기본적으로 입력을 허용하고 기본적으로 잘못된 위치를 보낼 것으로 예상하기 때문에 항상 무언가에 있음). ), 그러나 FD 1은 꺼져 있습니다. 파일 설명자 3 이상도 닫힐 수 있습니다.

즉, cmd파일이 열리면(예 open("some-file", O_WRONLY, 0600): ) 첫 번째 무료 파일 설명자에서 열리고 fd는 1이 됩니다! 이는 some-file이후에 표준 출력의 위치가 된다는 것을 의미합니다. 예를 들어, printf("Please enter your name: ")나중에 발생하면 some-file!

이는 (수십년 동안) setuid 실행 파일을 악용하는 방법이었습니다.

예를 들어, chshsetuid 실행 파일을 /etc/passwd편집하여 사용자 요청에 따라 사용자의 로그인 쉘을 변경할 수 있습니다.

그리고:

chsh >&-

chsh/etc/passwdfd 1에서 a를 열고 그곳의 사용자에게 보내려는 메시지를 작성하게 될 수도 있습니다 .

이 문제를 인식한 후 소프트웨어는 시작 시 fd 0, 1 또는 2가 닫혔는지 확인하고 닫혀 있으면 /dev/null열어서 이를 방지하기 시작했습니다.

나는 이것이 적어도 setuid 실행 파일이나 다른 민감한 컨텍스트로 실행되고 있음을 감지할 때 GNU libc(GNU 시스템의 모든 실행 파일에서 사용됨)가 수행하는 작업이라는 것을 기억하는 것 같지만 지금은 확인할 수 없습니다. I 그들은 그것을 잘못 기억했거나 행동을 바꿨습니다.

아무튼 tee지금 GNU 소스코드를 보면 쓰기용으로 파일을 열 때 다음과 같이 사용합니다.fopen_safer()gnulib의 변형(GNU libc 아님) fopen(), fd fopen()<= 2를 사용하는 경우 2보다 높은 fd로 이동합니다.

따라서 적어도 tee aa bb cc >&-이 구현을 사용하면 2(아마도 3) 이상의 첫 번째 fd가 열리고 다음 fd가 열리는 식으로 계속 진행되며 1은 닫힌 상태로 유지되므로 다음을 볼 수 있습니다.teeaabb

$ echo test | tee aa bb cc >&-
tee: 'standard output': Bad file descriptor

teefd 1(stdout)이 닫혀 있는 동안 쓸 수 없을 때 오류를 보고합니다.

busybox의 경우 에는 gnulib의 것을 tee사용하지 않으며 ,fopen_safer()

$ echo test | busybox tee aa bb cc >&-
$ cat aa
test
test

aa실제로는 fd 1에 있는데, 이는 test거기에 두 번 기록되는 이유를 설명합니다. 한 번은 stdout(fd 1)에 기록되었기 때문이고, 다른 한 번은 열린 fd aa(또한 fd 1)에 기록되었기 때문입니다.

teestdout(또는 다른 명령)을 삭제하려면 다음을 수행해야 한다는 점을 분명히 하기를 바랍니다.아니요닫고 /dev/null로 리디렉션합니다.

echo test | tee aa bb cc > /dev/null

하지만 여기서는 버리는 대신 다음과 같이 할 수 있습니다.

echo test | tee aa bb > cc
echo test | tee aa bb cc >&-

tee위에서 언급한 것처럼 보호 조치로 stdout이 닫혔다는 것을 감지하고 /dev/null에서 다시 여는 구현의 경우에만 이는 GNU tee나 busybox의 경우 가 아닙니다 tee(적어도 현재 버전 GNU 라이브러리).

stdout(또는 stdin 또는 stderr)을 끄려는 몇 가지 이유는 다음과 같습니다.

  • 실행 시 권한을 높이지만 이러한 병리학적 사례에서는 제대로 작동하지 않는 setuid/setgid 또는 보다 일반적인 소프트웨어를 악용하세요.

  • 소프트웨어를 테스트하여 이러한 조건에서 제대로 작동하는지 확인하십시오.

  • in 에서는 zsh출력 cmd1 > file | cmd2을 파이프 와 파이프 cmd1모두에 보냅니다 ( 내부적으로 수행되고 더 유연하다는 점을 제외하면 ing 과 유사함).filecmd2cmd1 | tee file | cmd2tee

    cmd1stderr을 로 보내고 stdout을 으로 보내려는 경우 stderr은 으로 보내고 stdout은 으로 cmd2 보낼 수 없습니다 .filecmd1 2>&1 > file | cmd2cmd2filecmd2

    tee다음을 수행하여 비활성화할 수 있습니다.

    cmd1 2>&1 >&- > file | cmd2
    

    다음과 같이 할 수도 있습니다.

    { cmd1 2>&1 > file; } | cmd2
    

    또는

    cmd1 > file 2> >(cmd2)
    

또는 1<&-그 문제에 대해 >&-및 사이의 유일한 차이점은 <&-지정되지 않은 경우 작동하는 fd입니다(각각 1과 0). 그들 모두는 단지 하나를 만들었습니다 close(fd).

관련 정보