OS X、bash:開いたファイル記述子では動作しませんが、catは機能しません。

OS X、bash:開いたファイル記述子では動作しませんが、catは機能しません。

私が作業している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/xfd 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が得られるからですcatfile

他のシステムでは

cat /dev/fd/5

catfd 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

関連情報