">&1"과 ">/proc/self/fd/1" 리디렉션의 차이점은 무엇입니까?

">&1"과 ">/proc/self/fd/1" 리디렉션의 차이점은 무엇입니까?

저는 시작 시 실행되는 일부 스크립트를 작업하고 rc.local있는데 출력 리디렉션이 매우 이상한 방식으로 작동하는 것을 발견했습니다.

그런 식으로 작성하면 echo "foo" >&1시스템 로그에 기록되고 모든 것이 정상입니다.

echo "foo" >>/dev/stdout하지만 , 또는 라고 쓰면 echo "foo" >>/proc/self/fd/1No such device or address라는 오류가 발생합니다.

추가 조사에 따르면 이는 /proc/self/fd/1실제로 소켓이었습니다. ls -l /proc/self/fd인쇄 콘텐츠에는 rc.local다음이 포함됩니다.

lr-x------. 1 root root 64 Jul 14 05:28 0 -> /dev/null
lrwx------. 1 root root 64 Jul 14 05:28 1 -> socket:[18485]
lrwx------. 1 root root 64 Jul 14 05:28 2 -> socket:[18485]
lr-x------. 1 root root 64 Jul 14 05:28 255 -> /etc/rc.d/rc.local

설명된 동작은 를 사용하여 쉽게 재현할 수 있습니다 nc. 먼저, 어떤 파일 설명자가 소켓에 바인딩되어 있는지 알아보세요. nc -l -p 25566 -c "ls -l /proc/self/fd"첫 번째 터미널에서 발행한 다음 telnet localhost 25566다른 터미널에서 발행 하여 이를 수행할 수 있습니다 . 제 경우에는 다섯 번째 설명자입니다.

좋아요 그런 다음 첫 번째 터미널에서 문제를 재현하려면 다음을 수행하십시오.

nc -l -p 25566 -c "echo 'hello' >&5"

두 번째 터미널에서:

telnet localhost 25566

연결 설정 및 종료를 위한 텔넷 메시지 사이의 두 번째 터미널 출력에 "hello"가 표시됩니다.

이제 일어나는 일은 파일 설명자 의사 파일이 다음에서 온다는 것입니다 /proc.

첫 번째 터미널:

nc -l -p 25566 -c "echo 'hello' >/proc/self/fd/5"

두 번째 터미널:

telnet localhost 25566

이제 두 번째 터미널에는 연결이 설정되고 즉시 닫히는 것에 대한 텔넷 메시지만 포함되며 첫 번째 터미널에는 오류가 표시됩니다 sh: /proc/self/fd/5: No such device or address.

편집하다:운영 체제는 Fedora 23 i686 서버입니다.


자, 여기서 문제가 발생합니다. >&1이들그리고 그리고 의 차이점은 무엇인가요 >/proc/self/fd/1? 현재 표준 출력과 정확히 일치하는 일부 파일로 출력을 리디렉션하는 일반적이고 안정적인 방법이 있습니까?

감사해요.


편집 2:

명확성을 위해 위 시나리오에서 Fedora 23 i686의 정확한 입력/출력은 다음과 같습니다.

Terminal 1                                       | Terminal 2
$ nc -l -p 25566 -c 'ls -go /proc/self/fd'       | 
                                                 | $ telnet localhost 25566
                                                 | Trying ::1...
                                                 | Connected to localhost.
                                                 | Escape character is '^]'.
                                                 | total 0
                                                 | lr-x------ 1 64 Jul 14 08:56 0 -> pipe:[19687]
                                                 | l-wx------ 1 64 Jul 14 08:56 1 -> pipe:[19688]
                                                 | lrwx------ 1 64 Jul 14 08:56 2 -> /dev/tty2
                                                 | lr-x------ 1 64 Jul 14 08:56 3 -> pipe:[19687]
                                                 | lr-x------ 1 64 Jul 14 08:56 4 -> /proc/1285/fd
                                                 | lrwx------ 1 64 Jul 14 08:56 5 -> socket:[19686]
                                                 | l-wx------ 1 64 Jul 14 08:56 7 -> /pipe:[19688]
                                                 | Connection closed by foreign host.
$ nc -l -p 25566 -c "echo 'hi' >&5"              | 
                                                 | $ telnet localhost 25566
                                                 | Trying ::1...
                                                 | Connected to localhost.
                                                 | Escape character is '^]'.
                                                 | hi
                                                 | Connection closed by foreign host.
$ nc -l -p 25566 -c "echo 'hi' >/proc/self/fd/5" | 
                                                 | $ telnet localhost 25566
                                                 | Trying ::1...
                                                 | Connected to localhost.
sh: /proc/self/fd/5: No such device or address   | Escape character is '^]'.
                                                 | Connection closed by foreign host.
$                                                | $

답변1

사용 >&N. 이것은 이식 가능하며 보시다시피 실제로 소켓과 함께 작동합니다.

사용하는 유일한 이유 /proc/self/fd는 파일 이름이 필요한 프로그램을 실행 중이고 이미 열려 있는 파일 설명자를 사용하라는 지시를 받을 수 없는 경우입니다. 예를 들어, <(cmd...)거의 모든 명령줄 유틸리티가 이름으로 지정된 파일을 열 수 있지만 모든 명령줄 유틸리티가 미리 열린 파일 설명자를 직접 지원하는 것은 아니기 때문에 리디렉션에서는 이를 사용합니다.

그러나 쉘은 기존 파일 설명자를 사용할 수 있으므로 /proc.


또한 이는 Linux에만 해당되며 내 Linux 시스템에 , 및 다른 항목은 등에 대한 심볼릭 링크 이므로 /proc/NNN/fd/설치 해야 합니다. 다른 유닉스에서는 다를 수 있습니다. ~에 따르면/proc/dev/stdout/dev/fd/*/proc/self/fd/*/proc오래된 질문에 대한 답변 /dev/stdoutPOSIX 외부로 명시적으로 나열됩니다.

리디렉션이 원하는 대로 작동하지 않는 이유는 다음과 같습니다. 을 사용해 보십시오. 두 strace가지의 차이점은 >&N리디렉션 의 경우 파일 설명자가 bash호출되며 .txt를 사용하여 일반 파일로 열려고 시도한다는 것입니다. . 이와 같은 새 소켓 복사본을 여는 것은 분명히 지원되지 않으므로 호출이 실패합니다. 스트림 소켓은 거의 지점 간 링크이므로 새 복사본 열기를 비활성화하는 것이 그다지 부자연스러워 보이지는 않습니다. 하지만 왜 파이프나 와 함께 작동하는지 모르겠습니다.dup()>/proc/self/fd/Nopen()procdup

$ ls -l /proc/self/fd/3
lrwx------ 1 itvirta itvirta 64 Jul 14 18:24 /proc/self/fd/3 -> socket:[168157]
$ strace bash -c "echo foo >>/proc/self/fd/3" 2>&1 | grep open.*proc/self
open("/proc/self/fd/3", O_WRONLY|O_CREAT|O_APPEND, 0666) = -1 ENXIO (No such device or address)

반품이 답변이식성에 관한 몇 가지 정보가 있습니다./proc/NNN/fd

답변2

3>&1기존 리디렉션 반복 과 유사파일 설명자: 이는 동일한 열린 파일(동일한 파일, 동일한 플래그, 동일한 위치 등)을 가져와 프로그램의 다른 "출력 포트"(다른 파일 설명자 번호)에 삽입합니다. (보다 정확하게는 동일한 파일 설명자를 가리키는 새 파일 설명자를 생성합니다.)파일 설명, 그러나 우리는 그렇지 않습니다)

>&1설명자를 자체에 복사하며 일부 쉘은 이를 완전히 최적화합니다.

>/proc/$pid/fd/1파일 열기와 같은 리디렉션입니다 /proc/$pid/fd/1. 그러면 새 파일 설명자가 생성됩니다. 의 파일은 /proc/*/fd파일을 열 때 기본적으로 기존 파일 설명자의 데이터를 복사한다는 점에서 특별합니다. 이러한 파일은 기호 링크이지만 "마법"입니다. 예를 들어 삭제된 파일이나 파이프는 깨진 기호 링크로 나타나지만 커널에 /proc/*/fd항목을 처리하는 특수 코드가 포함되어 있기 때문에 여전히 기존 파일처럼 열 수 있습니다. 따라서 대부분의 경우 >&1>/proc/self/fd/1는 동일합니다. 하지만,소켓은 다르게 취급됩니다..

/*
 *      In theory you can't get an open on this inode, but /proc provides
 *      a back door. Remember to keep it shut otherwise you'll let the
 *      creepy crawlies in.
 */

static int sock_no_open(struct inode *irrelevant, struct file *dontcare)
{
        return -ENXIO;
}

(최근 버전에서는 코드가 재구성되었으나, 여전히 소켓을 통과해도 열 수 없습니다 /proc/PID/fd/NUM.)

대부분의 다른 파일 형식처럼 소켓을 열 수 없는 이유는 소켓에 더 많은 정보가 첨부되어 있고 소켓을 여는 방법을 알려주어야 하기 때문입니다. 예를 들어 TCP 소켓을 열면 소스 포트가 할당됩니다. 어떤 경우에는 이것이 의미가 있을 수 있지만 Linux 커널은 다른 프로세스에 대한 소켓 열기를 허용하지 않습니다. 동일한 프로세스( /proc/self/fd/NUM대신 ) 의 경우 /proc/OTHERPID/fd/NUM호출을 open일반적인 파일 설명자 중복으로 변환할 수 있지만 /proc/self/fd애초에 여는 것은 특이한 일이며 일반적으로 기능 여유가 없기 때문에 소켓 리디렉션은 수행되지 않습니다. , 따라서 커널은 이 합리적이지만 쓸모없는 예외를 지원하도록 설계되지 않았습니다.

관련 정보