다양한 쉘의 fd 수가 고정되어 있습니까?

다양한 쉘의 fd 수가 고정되어 있습니까?

가정:

xb@dnxb:/tmp$ echo 'ls -l /proc/$$/fd | grep a.sh' > a.sh; \
> while IFS='' read -r f; do \
> echo "$f"; "$f" a.sh; \
> done < <(tail -n +2 /etc/shells)
/bin/sh
lr-x------ 1 xiaobai xiaobai 64 Jan  20 00:09 10 -> /tmp/a.sh
/bin/dash
lr-x------ 1 xiaobai xiaobai 64 Jan  20 00:09 10 -> /tmp/a.sh
/bin/bash
lr-x------ 1 xiaobai xiaobai 64 Jan  20 00:09 255 -> /tmp/a.sh
/bin/rbash
lr-x------ 1 xiaobai xiaobai 64 Jan  20 00:09 255 -> /tmp/a.sh
/bin/zsh
lr-x------ 1 xiaobai xiaobai 64 Jan  20 00:09 11 -> /tmp/a.sh
/usr/bin/zsh
lr-x------ 1 xiaobai xiaobai 64 Jan  20 00:09 11 -> /tmp/a.sh
/bin/ksh93
lr-x------ 1 xiaobai xiaobai 64 Jan  20 00:09 10 -> /tmp/a.sh
/bin/rksh93
lr-x------ 1 xiaobai xiaobai 64 Jan  20 00:09 10 -> /tmp/a.sh
xb@dnxb:/tmp$ 

기본적으로 bash는 항상 fd 번호 255를 수정하고 zsh는 fd 번호 11을 수정합니까?

쉘 프로세스에서 실행되는 전체 경로를 추출해야 하기 때문에 이 질문을 드리는 것입니다. 이 고정 숫자를 인용하거나 인용하지 않도록 스크립트를 하드코딩할 수 있는지 궁금합니다.

이것은 개인 스크립트용이며 비즈니스에 중요한 기반으로 실행되도록 의도된 것이 아니므로 100% 신뢰할 수 있는 스크립트를 찾고 있지는 않습니다.대부분의 경우 fd 번호는 고정되어 있습니까??

[고쳐 쓰다]:

분석을 하지 않는 이유는 cmdline다음과 같습니다.

xb@dnxb:~/Downloads$ cat foo.sh 
#!/bin/bash
cat "/proc/$$/cmdline" | tr '\0' '\n'
readlink -f /proc/$$/fd/255

xb@dnxb:~/Downloads$ bash --norc foo.sh --norc
bash
--norc
foo.sh
--norc
/home/xiaobai/Downloads/foo.sh
xb@dnxb:~/Downloads$ 

보시다시피, fd전체 경로만 제공할 수 있지만 /home/xiaobai/Downloads/foo.sh는 제공할 수 없습니다 cmdline. 스크립트는 시작하지 않는 것처럼 추악한 검사를 수행하지 않는 한 모든 옵션 위치에 나타날 수 있는 경로나 옵션을 구분할 수 foo.sh없습니다 . .--norcfoo.sh--

fd이렇게 해도 문제 없이 올바른 전체 경로가 생성됩니다 bash --norc foo.sh --norc foo2.sh.

어쨌든, 나는 사용자 정의 프로세스 이외의 시스템 프로세스가 셸에서 상속되지 않는다는 것을 알았기 때문에 내 작업에서 이를 확인할 필요가 없다는 것을 깨달았습니다. 그러나 어떤 대답이라도 미래의 독자들에게는 여전히 도움이 될 것입니다.

답변1

당신이 확신할 수 있는 유일한 것은 fds 1부터 9가 아니라는 것입니다. 이는 POSIX sh 구현에서 사용자 사용을 위해 예약되어 있고 sh < your-script이 경우 0을 사용할 수 있기 때문입니다. yash는 이를 fds 1에서 99까지 확장합니다.

시작할 때 해당 fd가 열려 있으면 쉘이 다른 값을 사용하기 때문에 이를 고정 값으로 신뢰할 수 없습니다. 대부분의 쉘은 내부 fd로 9(yash의 경우 99) 이상의 첫 번째 자유 fd를 사용하는 것 같습니다. bash255를 사용하고 사용할 수 없을 때 올라가는 대신 내려가는 것 같습니다.

bash-5.0$ bash a 255> /dev/null
total 0
lrwx------ 1 chazelas chazelas 64 Sep 26 18:03 0 -> /dev/pts/12
lrwx------ 1 chazelas chazelas 64 Sep 26 18:03 1 -> /dev/pts/12
lrwx------ 1 chazelas chazelas 64 Sep 26 18:03 2 -> /dev/pts/12
lr-x------ 1 chazelas chazelas 64 Sep 26 18:03 254 -> /home/chazelas/a
l-wx------ 1 chazelas chazelas 64 Sep 26 18:03 255 -> /dev/null
bash-5.0$ ulimit -n 123
bash-5.0$ bash a
total 0
lrwx------ 1 chazelas chazelas 64 Sep 26 18:03 0 -> /dev/pts/12
lrwx------ 1 chazelas chazelas 64 Sep 26 18:03 1 -> /dev/pts/12
lr-x------ 1 chazelas chazelas 64 Sep 26 18:03 122 -> /home/chazelas/a
lrwx------ 1 chazelas chazelas 64 Sep 26 18:03 2 -> /dev/pts/12

$0일반적으로 실행 중인 스크립트의 경로 가져오기를 사용하는 것이 가장 좋은 방법입니다. 또한보십시오:$0에는 항상 스크립트 경로가 포함되어 있습니까?

답변2

/proc/<pid>/cmdline위의 내 의견을 확장하면 이를 사용 하여 관심 있는 정보를 얻을 수 있습니다 . 토큰은 NIL 문자로 구분되므로 출력을 일부 처리해야 합니다.

cat /proc/<pid>/cmdline | tr "\0" " "

그래서 내가 가진 경우 :

$ cat foo.sh
#!/bin/bash
echo $(cat "/proc/$$/cmdline" | tr "\0" " ")

다음은 몇 가지 실행 예시입니다.

$ bash foo.sh
bash foo.sh

$ ./foo.sh
/bin/bash ./foo.sh

$ ./foo.sh 1 2 3 4
/bin/bash ./foo.sh 1 2 3 4

이것이 항상 바이너리에 대한 전체 경로를 제공하는 것은 아닙니다. 이렇게 하려면 다음을 확인하세요 /proc/<pid/exe.

$ ls -l /proc/$$/exe
... /proc/12345/exe -> /bin/bash

이것은 아마도 당신이 원하는 것이 아닐 것입니다. 열린 파일 설명자를 보는 것이 당신이 원하는 것을 어떻게 얻을 수 있는지 모르겠습니다.

관련 정보