파일 설명자 6을 읽으려면 <&6
또는 </dev/fd/6
(일명 /proc/self/fd/6
)을 사용할 수 있습니다. 종종 둘 다 똑같이 효과적입니다. 그러나 해당 파일 설명자가 소켓인 경우 이상한 일이 발생합니다. 예를 들어:
$ bash -c 'ls -l /dev/fd/6;cat /dev/fd/6' 6</dev/tcp/localhost/12345
lrwx------ 1 michas michas 64 Jan 10 19:50 /dev/fd/6 -> socket:[315010]
cat: /dev/fd/6: No such device or address
이는 ls
설명자가 존재함을 나타냅니다. 하지만 이런 방식으로 데이터에 접근하는 것은 불가능합니다. 사용하면 cat <&6
모든 것이 정상으로 돌아갑니다.
파일 설명자에 액세스하는 두 가지 방법의 차이점은 무엇입니까?
변수에 숫자가 주어진 경우 설명자에 액세스할 수 있는 좋은 방법이 있습니까? ( </dev/fd/$fd
예, 하지만 <&$fd
아닙니다.)
(위 내용은 Linux에서는 볼 수 있지만 OpenBSD에서는 볼 수 없습니다. - 파일 설명자가 일반 문자 장치인 것처럼 보입니다.)
답변1
그 이유는 /dev/fd/
Linux에는 소켓을 나타내는 항목에서 데이터를 읽는 구현이 없기 때문입니다.여기에서 추론에 관한 좋은 기사를 찾을 수 있습니다.따라서 해당 링크를 호출할 수 있으므로 stat
로 표시되지만 ls
의도적으로 비활성화됩니다.
이제 두 번째 부분으로 넘어가겠습니다. 왜 작동하나요 bash -c 'ls -l /dev/fd/6; cat <&6' 6</dev/tcp/localhost/12345
? 이는 /proc
파일 시스템 이 아닌 소켓/파일 API를 사용하여 소켓을 읽기 때문입니다 . 이것이 내가 관찰한 것입니다:
bash
터미널에서 실행 중인 인스턴스는 fd 6을 사용하여 소켓을 생성합니다.- 하위 프로세스가
bash
실행되고 소켓을 's'dup2(6, 0)
로 연결하기 위해 호출됩니다 .cat
stdin
dup2
호출이 실패하지 않으면 cat이 읽 습니다stdin
.
다음을 통해 재현하고 관찰할 수 있습니다.
netcat -lp 12345 # in another terminal session (GNU netcat)
strace -f -e trace=open,read,write,dup2 bash -c 'ls -l /dev/fd/6; cat <&6' \
6</dev/tcp/localhost/12345
하위 프로세스가 fd 6에 액세스할 수 있는 이유가 궁금하다면 bash
파일 설명자가 여전히 존재합니다 fork
.닫힘으로 표시되지 않은 경우 exec
닫히지 않습니다.
답변2
귀하의 직접적인 질문에 대답하기 위해 "차이점은 무엇입니까? ":
에서 리디렉션하면 <&6
셸은 dup2()
시스템 호출을 사용하여 파일 설명자를 복사합니다. </dev/fd/6
에서 리디렉션을 시도할 때 open()
.
커널은 open()
에서 소켓을 지원하지 않습니다. 소켓은 장식/dev/fd
정보 용으로만 디렉토리에 나타납니다 .