stdin が fd4 にリダイレクトされている場合、なぜ read が機能するのでしょうか?

stdin が fd4 にリダイレクトされている場合、なぜ read が機能するのでしょうか?

次のスクリプトはどういう意味ですか?

exec 4<&0 0</etc/XX/cfg
read line1
exec 0<&4

fd0 を fd4 にリダイレクトし、"/etc/XX/cfg" を fd0 にリダイレクトします。

では、なぜreadまだ機能するのでしょうか。空であるべきではないのでしょうか?

答え1

stdin (FD0) を FD4 にリダイレクトし、から を/etc/XX/cfgFD0 にリダイレクトし、FD0 から 1 行を読み取り、FD4 を FD0 に戻します。つまり、stdin を保存、置換、復元しながら、その間にファイルから 1 行読み取ります。

read line1 < /etc/XX/cfgはるかに簡単になりますが、表示されたコードだけに基づいて、それが有効な置換であるかどうかを判断することは不可能です。

答え2

これを syscalls で書き直すには (C を使用):

exec 4<&0 0</etc/XX/cfg

/* Duplicate fd0 as fd4.  */
dup2 (0, 4);

/* Open file on fd0.
   "open" always uses lowest available descriptor, so we don't need to check it. */
close (0);
open ("/etc/XX/cfg", O_RDONLY);

exec 0<&4

/* Close fd0 and duplicate fd4 as fd0.  */
dup2 (4, 0);

答え3

私がこれを解釈する方法は、bash のマニュアルページの REDIRECTION セクションに基づいて、stdin(fd0) が fd4 にリダイレクトされ、次に入力が/etc/XX/cfgそこから取得されstdin、最終的に fd4 に到達するというものです。

read line1次に fd4 から取得し、それを fd0 に戻します。

デモでは、私の意図をもう少しわかりやすく示し、「なぜ」これを行うのかという疑問に答えることができます。別の行を追加してラッパーに入れます。

$ vim ./test.sh
#!/bin/bash
exec 4<&0 0</etc/XX/cfg
read line1    # reads from fd4
exec 0<&4
read line2    # reads from fd0

echo $line1 
echo $line2

test.sh 経由でパイプまたはリダイレクトできますstdinが、リダイレクトによって構成を読み込むこともできます。そのため、上記のコードでは、「config」から値を取得しました (ファイル名に基づく私の推測 - よくありません :) )。ただし、stdin 経由でも処理できます。

例えば:

$ ./test.sh < somefile
$ cat somefile | ./test.sh

これで説明がつくと思います。

関連情報