必要なアプリケーションがあります。生産者ファイル名の送信消費者、そしてあります生産者指示する消費者最後のファイル名が転送されたときファイルの終わり達成。
簡略化のため、次の例では生産者 デモンストレーションにはとを使用しecho
、printf
デモには消費者を使用しますcat
。私は「ここにファイルを保存する」方法を推論しようとしましたが、成功しませんでした<<EOF
。プロデューサーラッパー(そのようなものが存在する場合)ファイルの終わり。有効な場合は、出力からフィルタリングcat
する必要があります。EOF
例1)
入力する
{
echo "Hello World!"
printf '\x04'
echo "EOF"
} <<EOF |\
cat
出力
bash: warning: here-document at line 146 delimited by end-of-file (wanted `EOF')
Hello World!
EOF
例2)
入力する
{
echo "Hello World!"
printf '\x04'
echo "EOF"
} |\
cat <<EOF
出力
bash: warning: here-document at line 153 delimited by end-of-file (wanted `EOF')
区切り文字を表示するための「ここにファイルを保存する」方法は、静的テキストでのみ機能し、動的に生成されたテキストでは機能しないことは正しいですか?
--実用的なアプリケーション--
inotifywait -m --format '%w%f' /Dir | <consumer>
コンシューマは /Dir ディレクトリにファイルが書き込まれるのを待っています。 「/Dir/EOF」ファイルが作成されると、コンシューマは次のようにシェルスクリプトを作成して論理ファイルの終了条件を検出できます。
inotifywait -m --format '%w%f' /Dir |<</Dir/EOF <consumer>
——ザイルズの回答に対する回答——
理論的に可能ですか?
cat <<EOF
hello
world
EOF
〜のように
SpecialSymbol="EOF"
{
echo hello
echo world
echo $SpecialSymbol
} |\
while read Line; do
if [[ $Line == $SpecialSymbol ]]
break
else
echo $Line
fi
done |\
cat
理論的には、たぶん私の言葉は「既存の使用パターンをサポートし、以前に違法な構文を持つ追加使用パターンのみを有効にしますか?」- 既存の法律および規制が損なわれないことを意味します。
答え1
パイプの場合、すべてのプロデューサがパイプのファイル記述子を閉じ、消費者がすべてのデータを読み取った後、消費者はファイルの終わりを表示します。
したがって:
{
echo foo
echo bar
} | cat
cat
echo
2番目のエントリが終了し、合計がcat
読み込まれると、ファイルの終わりが表示されます。もうやることはありません。foo\n
bar\n
ただし、覚えておくべきことは、パイプの左側のコマンドの一部がバックグラウンドプロセスを開始すると、そのバックグラウンドプロセスがパイプのfd(stdout)を継承するため、そのcat
プロセスも終了するまでeofまたは終了が表示されないことです。標準出力。良い:
{
echo foo
sleep 10 &
echo bar
} | cat
cat
返品なしで10秒経過したことがわかります。
sleep
ここでstdoutを別のものにリダイレクトできます。たとえば、/dev/null
対応する(非)出力が次に供給されることを望まない場合cat
:
{
echo foo
sleep 10 > /dev/null &
echo bar
} | cat
左側のサブシェルで最後のコマンドを実行する前にパイプの書き込み端を閉じるには、stdoutを|
閉じるか、中央のサブシェルにリダイレクトを使用できますexec
。たとえば、次のようになります。
{
echo foo
exec > /dev/null
sleep 10
} | (cat; echo "cat is now gone")
ただし、ほとんどのシェルはコマンドに加えてこのサブシェルを待ちますcat
。したがって、読んだcat is now gone
直後に表示できますが、foo
パイプライン全体が完了するまで10秒待つ必要があります。もちろん、上記の例では、次のように書く方が合理的です。
echo foo | cat
sleep 10
<<ANYTHING...content...ANYTHING
コマンドの標準入力を以下を含むファイルにするここのドキュメントです。コンテンツ。そこには役に立たない。\4
は、端末から読み取られたときに端末装置に格納されているデータがデータを読み取るアプリケーションにフラッシュされるバイトです(データがない場合はread()
0が返され、ファイルの終わりを示します)。繰り返しますが、ここでは役に立ちません。
答え2
あなたの試みの問題は、あなたが「ここにファイルを保存する方法」と呼ぶものが存在しないことです。ここにあるファイルはシェルプログラミング言語の構文機能です。たとえば、に置き換えられませんcat
。
ここにドキュメントを含むシェルスクリプトを考えてみましょう。
cat <<EOF
hello
world
EOF
どのように機能するかは、スクリプトの解析中にシェルインタプリタがhereドキュメントの構文構造を見ることです。これらのコード行を実行すると、インタプリタはデータを収集してcat
シェルに従ってinputに渡します。
echo 'hello
world
' >/tmp/heredoc.tmp
cat </tmp/heredoc.tmp
rm /tmp/heredoc.tmp
(ただし、一時ファイルのより賢明な管理)または
echo 'hello
world
' | cat
echo EOF
ここで文書の終わりを示す場合は、コマンドの出力はecho
シェルでなければなりません。
{
echo 'cat <<EOF'
echo hello
echo world
echo EOF
} | sh
これはうまくいきますが、ほとんど役に立ちません。
これらのどれもあなたが計画したことを達成するのを助けません。ここにあるドキュメントには、他の入力よりも終わりが「より難しく」する魔法のようなものはありません。ファイルの終わりは、入力チャンネルを介して送信されるマーカーではなく、入力チャンネルの条件です。入力が通常のファイルの場合、アプリケーションがファイルの最後のバイトを読み取ろうとすると、ファイルの終了条件がトリガーされます。入力がパイプ(名前が指定または指定されていない)の場合、アプリケーションは読み取りを試みますが、プロデューサーがパイプを閉じるとファイル終了条件がトリガーされます。
普通は書くだけで十分です。
producer | consumer
終了すると、producer
パイプの書き込み終了は開いているプロセスがないため閉じられます。パイプを早く閉じるには、生産者が標準出力(exec >&-
sh、close(1)
C)を閉じる準備をします。
パイプのファイルの終わりに達するには、パイプの書き込み側を開いたすべてのプロセスがパイプを閉じる必要があります。プロデューサがバックグラウンドプロセスを実行している場合は、fcntl(1, F_SETFD, fcntl(1, F_GETFC, 0) | FD_CLOEXEC)
パイプ()をフォークする前に実行時に閉じるフラグを設定する必要があります。
答え3
FIFOを使用したい場合は、もちろん次のようにすることができます。
スクリプト1
FIFO_PATH="/path/to/fifo"
exec 3<"$FIFO_PATH" # stalls until FIFO is opened for writing, too
while read line; do
: whatever
done <&3
exec 3<&-
: continue script
スクリプト2
FIFO_PATH="/path/to/fifo"
exec 3>"$FIFO_PATH" # stalls until FIFO is opened for reading, too
echo foo >&4
exec 4>&-
: continue script