私が作業している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
ファイルの内容は I を使用して両方で表示できます。
以下を使用して、上記の効果(両方のOSで動作)を達成することができました。
less /dev/fd/5 | tee
しかし、これはハッキングのようです。
less
それでは、OS Xでは見えないものを見ることが明らかに可能な理由は何ですか?cat
(あるいは、すべてのBSDの子孫が影響を受けますか?)
それとも私が何か間違っているのでしょうか?
答え1
OS Xでは、これをサポートするすべてのシステムと同様にLinuxを除く/dev/fd/x
, a 実行と同様に開くと、dup(x)
結果 fd は fd x とほぼ同じオープンファイル記述、特にファイル内で同じオフセットを指します。
ここでは、Linuxは例外です。 Linuxでは、/dev/fd/x
fd xで開かれたファイルへのシンボリックリンクであり、疑似シンボリック/proc/self/fd/x
リンク/proc/self/fd/x
です。 Linuxでは、を実行するとopen("/dev/fd/x", somemode)
まったく新しいものが得られます。ファイル説明を開く開いたファイルと同じファイルにx
。あなたが得る新しいfdはfd xとは何の関係もありません。特に、オフセットはファイルの先頭にあります(もちろん、O_APPEND
リバースモードでパイプを開くときにもう一方の端で開かない限り)。 (これはまたソケットでは動作しないことを意味します。開いている())。
したがって、Linuxでは、次のことを行うとき
exec 5<> file
echo test >&5
fd 5 のオフセットはファイルの末尾にあります。そうすれば
cat <&5
あなたは何も得られません。
または、次のような場合:
cat /dev/fd/5
ご覧のとおりtest
、fd 5とは関係のない新しい読み取り専用fdが得られるからですcat
。file
他のシステムでは
cat /dev/fd/5
cat
fd 5と重複したfdをインポートすると、ファイルの末尾にまだオフセットがあります。
これが機能する理由は、何らかの理由でaがless
そのfdからファイルの先頭までless
実行されるためです(aはファイルを検索できることを確認するために実行されます)。lseek()
lseek(1); lseek(0)
ここで、2 つの fd が異なるオフセットを持つようにするには、読み取り用 fd 1 つと書き込み用 fd 1 を持たせたい場合があります。
exec 5< file 9>&1 > file
または、ファイルがまだ存在する場合は、そのファイルを再度開くか、lseek()
同じless
操作を実行する必要があります。
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