
以下は、すべての出力をファイルにリダイレクトし、画面に出力を表示するbashスクリプトの例です。
# writing to it
exec > >(tee --ignore-interrupts ./log)
exec 2>&1
echo "here is a message"
# reading from it again
cat ./log
これでファイルを作成したくありません./log
。すべてのstdoutをメモリに保存し、後でスクリプトから再読み込みできるようにしたいです。また、ルートファイルシステムがマウントされない状況にあります。
代わりに、プロセス置換を試してみましたが、作成した内容を./log
読み取るために、後続のコマンドのプロセス置換によって生成されたファイル記述子を渡す方法がわからないようです。
別の例は次のとおりです。
# can I make ./log a temporary file descriptor, an in-memory buffer?
exec 3>./log 4<./log
# writes
echo >&3 "hello"
# reads
cat <&4
答え1
作成されたすべてのコンテンツをグローバルにリダイレクトしたい場合は(今のように)トリッキーですが、まとめることができます。
可能であれば、通常のパイプを使用することをお勧めします。サブシェルで実行するすべての作業をラップするだけです。この場合
(
echo "this is the message"
other stuff
) | cat
または、単に "$()" 構文を使用してすべてを変数に書き込みます。
次の方法は、あなたがしたものを使用し、tmpfsに書き込むか、または/dev/shm
利用可能な場合に書き込むことです。非常にシンプルですが、どのRAMベースのファイルシステムがあるかを知る必要があります(可能であれば設定する必要があります)。
もう一つの方法はmkfifo
。どちらの場合も、自分で掃除する必要があります。
編集する:
本当に醜いハッキングがありますが、誰かがそれを改善できると確信しています。
#!/bin/bash
exec 3>&1
exec > >( tee >( ( tac && echo _ ) | tac | (read && cat > ./log) ) )
echo "lol"
sleep 5
echo "lol"
echo "finished writing"
exec >&-
exec >&3
exec 3>&-
echo "stdout now reopen"
sleep 1 #wait if the file is still being written asynchronously
cat ./log
仕組み:まず、tee
何が起こっているのかを確認することができます。その後、交換のために別のプロセスに出力されます。続行する前に、ストリーム全体が完了するのを待つトリックtac|tac
(tac
出力を開始するには完全な入力が必要なので)があります。最後の部分は実際にファイルとして出力するサブシェルにあります。もちろん、最終シェルはインスタンス化直後にファイルシステムに出力ファイルを生成します(唯一の行の場合)。したがって、入力が最終的に到着するのを待ってファイルの生成を遅らせる作業を最初に実行する必要があります。まず、echoを使用してダミーラインを出力し、それを読み取って削除してこれを達成しました。これらのread
ブロックは、ファイル記述子を閉じてtac
その時間が満了したことを示すまでブロックされます。したがって、stdoutファイル記述子は最終的に閉じられます。また、プロセスの交換をオンにする前に、元のファイルを保存してstdout
最後に復元することができました(cat
再利用のため)。そこに1つあるので、ファイルが実際に早すぎて作成されていないことをsleep 5
確認できます。ls
最後のスリープモードはもっとトリッキーです。サブシェルは非同期です。出力が多い場合は、tac
ファイルが実際に存在する前に2つの操作が完了するのを待ちます。したがって、合理的にタスクが実際に完了したことを確認するために他のタスクを実行したい場合があります。たとえば、ファイルを最後に使用する前に、最後のサブシェルの&& touch sentinel
最後に。while [ ! -f sentinel ]; do sleep 1; done && rm sentinel
全体として2つのプロセス交換があり、内部には2つのサブシェルと2つのパイプがあります。これは私が書いたものの中で最も醜いものの1つです...しかし、stdoutを閉じたときにのみファイルを生成する必要があります。これは、ファイルシステムの準備が整うとうまく制御され、完了できることを意味します。
答え2
簡単な場合:
output="$(echo "here is a message")"
# [...]
echo "$output"
リダイレクトで読む必要があり、次のパイプを使用できない場合はそれほど簡単ではありません。
echo "$output" | while IFS= read -r line; do :; done
FIFOとバックグラウンドプロセスが利用可能です。
mkfifo fifo
echo "$output" >fifo &
while IFS= read -r line; do :; done <fifo
Tシャツバージョン
mkfifo fifo
( output="$(cat fifo)"; echo "$output" >fifo ) &
exec 3>&1
exec >fifo
...
exec 1>&3
cat fifo