さまざまなシェルの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

これはおそらくあなたが望むものではありません。開かれたファイル記述子を見ると、あなたが望むものをどのように得ることができるかわかりません。

関連情報