私が取り組んでいるbashスクリプト(UbuntuとOS Xで実行する必要があります)では、何百ものコマンドの出力をファイルにリダイレクトする必要があります。
それらすべてに&>...
を追加するのではなく、単に
exec 9>&1
exec 5<>/tmp/some-file.txt
exec 1>&5
これまでのところ良好ですが、これらすべてのコマンドの途中で、ファイル記述子を開いたまま、これまでに書き込まれたすべてのものを読み取る必要があります。
今、Ubuntuでは簡単にできます
cat /dev/fd/5
または
tee </dev/fd/5
ただし、OS Xでは、何も出力されません(コマンドはすぐに終了します)。
ただし、less
を使用すると、両方のファイルの内容を確認できます。
上記の効果(両方のOSで動作)を使用することで達成できます
less /dev/fd/5 | tee
しかし、それはハックのようです。
では、なぜless
はOSXではcat
が見ることができないものを明らかに見ることができるのでしょうか。 (または、すべてのBSD子孫が影響を受けますか?)
それとも私は何か間違ったことをしていますか?
OS Xでは、サポートされているすべてのシステムと同様にLinuxを除く、/dev/fd/x
を開くことは、dup(x)
を実行することと同じであり、結果のfdは多かれ少なかれ同じオープンを指します。 fd xと同様のファイル記述、特にファイル内で同じオフセットがあります。
Linuxはここでは例外です。 Linuxでは、/dev/fd/x
は/proc/self/fd/x
へのシンボリックリンクであり、/proc/self/fd/x
はfdxで開いているファイルへの疑似シンボリックリンクです。 Linuxでopen("/dev/fd/x", somemode)
を実行すると、x
で開くのと同じファイルにまったく新しいファイルの説明を開くが表示されます。取得した新しいfdは、fdxとはまったく関係ありません。特に、オフセットはファイルの先頭にあり(もちろん、O_APPEND
で開く場合を除く)、モード(読み取り/書き込み/追加...)はfdxのものとは異なる場合があります。 (反対のモードでパイプを開いたときのパイプのもう一方の端のように、fd xにあるものとはまったく異なるものを取得することもできます)。 (これは、たとえば、できないソケットでは機能しないことも意味しますopen())。
したがって、Linuxでは、
exec 5<> file
echo test >&5
Fd5のオフセットはファイルの最後にあります。もしあなたがそうするなら
cat <&5
何も得られません。
それでもあなたがするとき:
cat /dev/fd/5
test
がfd5とは関係のないcat
への新しい読み取り専用fdを取得するため、file
が表示されます。
他のシステムでは、
cat /dev/fd/5
cat
は、fd 5の複製であるfdを取得するため、ファイルの最後にオフセットがあります。
less
で機能する理由は、何らかの理由で、less
がファイルの先頭までのfdでlseek()
を実行する(lseek(1); lseek(0)
を実行する)ためです。ファイルがシーク可能かどうかを判断するため)。
ここで、両方に異なるオフセットを持たせたい場合は、読み取り用と書き込み用のfdが必要になる可能性があります。
exec 5< file 9>&1 > file
または、ファイルがまだある場合はファイルを再度開くか、less
のようにlseek()
を実行する必要があります。
ksh93
とzsh
は、lseek()
演算子が組み込まれている唯一のシェルです。
cat <&5 <#((0)) # ksh93
{sysseek 0; cat} <&5 # zsh, zmodload zsh/system to enable that builtin
または:
cat /dev/fd/5 5<#((0)) # ksh93
sysseek -u 5 0; cat /dev/fd/5 # zsh