名前付きパイプを使用して入力データを並列に処理し、結果を再度貼り付けようとします。標準入力(下)から入力を受け取る可能性を追加するまで、いくつかの作業がありました。この回答)。
ここでは、列のみを選択して貼り付ける前に追加の処理を行わない簡単な例を使用して問題を報告しますが、実際のスクリプトはそれ以上を行います。
データ例:
$ cat data.txt
A1 A2 A3 A4 A5
B1 B2 B3 B4 B5
C1 C2 C3 C4 C5
D1 D2 D3 D4 D5
E1 E2 E3 E4 E5
F1 F2 F3 F4 F5
G1 G2 G3 G4 G5
H1 H2 H3 H4 H5
I1 I2 I3 I4 I5
J1 J2 J3 J4 J5
K1 K2 K3 K4 K5
L1 L2 L3 L4 L5
一般ファイルを使用するスクリプト:
$ cat test_files.sh
#!/bin/bash
get_1()
{
cut -f1 - > ${1}
}
get_3()
{
cut -f3 - > ${1}
}
get_5()
{
cut -f5 - > ${1}
}
setup()
{
workdir=$(mktemp -d)
col1="${workdir}/col1.txt"
col3="${workdir}/col3.txt"
col5="${workdir}/col5.txt"
}
setup
cleanup()
{
rm -rf ${workdir}
}
if [ $# -ge 1 -a -f "${1}" ]
then
cat ${1} \
| tee >(get_1 ${col1}) \
| tee >(get_3 ${col3}) \
| get_5 ${col5} \
|| { echo "cat failed" && cleanup && exit 1; }
else
cat - \
| tee >(get_1 ${col1}) \
| tee >(get_3 ${col3}) \
| get_5 ${col5} \
|| { echo "cat failed" && cleanup && exit 1; }
fi
paste ${col1} ${col3} ${col5}
cleanup
exit 0
これは両方のモードでうまく機能します。
$ ./test_files.sh data.txt
A1 A3 A5
B1 B3 B5
C1 C3 C5
D1 D3 D5
E1 E3 E5
F1 F3 F5
G1 G3 G5
H1 H3 H5
I1 I3 I5
J1 J3 J5
K1 K3 K5
L1 L3 L5
$ cat data.txt | ./test_files.sh
A1 A3 A5
B1 B3 B5
C1 C3 C5
D1 D3 D5
E1 E3 E5
F1 F3 F5
G1 G3 G5
H1 H3 H5
I1 I3 I5
J1 J3 J5
K1 K3 K5
L1 L3 L5
以下はfifosを使用するバージョンです。私はバックグラウンドで熱抽出を行い、fifosから貼り付けます。
$ cat test_fifos.sh
#!/bin/bash
get_1()
{
cut -f1 - > ${1}
}
get_3()
{
cut -f3 - > ${1}
}
get_5()
{
cut -f5 - > ${1}
}
setup()
{
workdir=$(mktemp -d)
col1="${workdir}/col1.txt"
mkfifo ${col1}
col3="${workdir}/col3.txt"
mkfifo ${col3}
col5="${workdir}/col5.txt"
mkfifo ${col5}
}
setup
cleanup()
{
rm -rf ${workdir}
}
if [ $# -ge 1 -a -f "${1}" ]
then
cat ${1} \
| tee >(get_1 ${col1}) \
| tee >(get_3 ${col3}) \
| get_5 ${col5} \
|| { echo "cat failed" && cleanup && exit 1; } &
else
cat - \
| tee >(get_1 ${col1}) \
| tee >(get_3 ${col3}) \
| get_5 ${col5} \
|| { echo "cat failed" && cleanup && exit 1; } &
fi
paste ${col1} ${col3} ${col5}
cleanup
exit 0
入力ファイルを引数として使用すると機能します。
$ ./test_fifos.sh data.txt
A1 A3 A5
B1 B3 B5
C1 C3 C5
D1 D3 D5
E1 E3 E5
F1 F3 F5
G1 G3 G5
H1 H3 H5
I1 I3 I5
J1 J3 J5
K1 K3 K5
L1 L3 L5
ただし、stdinからデータをインポートするときに出力はありません。
$ cat data.txt | ./test_fifos.sh
$ # Nothing here, no error message
最小限の例を生成するために、いくつかの実験を実行しながら、潜在的に誤ったコードを処理することが問題の一部であるように見えました。以下は、fifosを使用してエラーを処理しないバージョンです。
$ cat test_fifos_noerr.sh
#!/bin/bash
get_1()
{
cut -f1 - > ${1}
}
get_3()
{
cut -f3 - > ${1}
}
get_5()
{
cut -f5 - > ${1}
}
setup()
{
workdir=$(mktemp -d)
col1="${workdir}/col1.txt"
mkfifo ${col1}
col3="${workdir}/col3.txt"
mkfifo ${col3}
col5="${workdir}/col5.txt"
mkfifo ${col5}
}
setup
cleanup()
{
rm -rf ${workdir}
}
if [ $# -ge 1 -a -f "${1}" ]
then
cat ${1} \
| tee >(get_1 ${col1}) \
| tee >(get_3 ${col3}) \
| get_5 ${col5} &
else
cat - \
| tee >(get_1 ${col1}) \
| tee >(get_3 ${col3}) \
| get_5 ${col5} &
fi
paste ${col1} ${col3} ${col5}
cleanup
exit 0
これは2つのモードで動作できます。
$ ./test_fifos_noerr.sh data.txt
A1 A3 A5
B1 B3 B5
C1 C3 C5
D1 D3 D5
E1 E3 E5
F1 F3 F5
G1 G3 G5
H1 H3 H5
I1 I3 I5
J1 J3 J5
K1 K3 K5
L1 L3 L5
$ cat data.txt | ./test_fifos_noerr.sh
A1 A3 A5
B1 B3 B5
C1 C3 C5
D1 D3 D5
E1 E3 E5
F1 F3 F5
G1 G3 G5
H1 H3 H5
I1 I3 I5
J1 J3 J5
K1 K3 K5
L1 L3 L5
stdinからデータを取得してfifosを使用したときに発生する可能性のあるエラーを処理するときに出力がないのはなぜですか?
編集:いくつかのデバッグ
失敗したスクリプトにいくつかのデバッグ出力を追加しました。
$ cat test_fifos.sh
#!/bin/bash
get_1()
{
>&2 echo "get_1"
cut -f1 - > ${1}
}
get_3()
{
>&2 echo "get_3"
cut -f3 - > ${1}
}
get_5()
{
>&2 echo "get_5"
cut -f5 - > ${1}
}
setup()
{
workdir=$(mktemp -d)
col1="${workdir}/col1.txt"
mkfifo ${col1}
col3="${workdir}/col3.txt"
mkfifo ${col3}
col5="${workdir}/col5.txt"
mkfifo ${col5}
}
setup
cleanup()
{
>&2 echo "cleanup"
rm -rf ${workdir}
}
if [ $# -ge 1 -a -f "${1}" ]
then
>&2 echo "then"
cat ${1} \
| tee >(get_1 ${col1}) \
| tee >(get_3 ${col3}) \
| get_5 ${col5} \
|| { >&2 echo "cat failed" && cleanup && exit 1; } &
else
>&2 echo "else"
cat - \
| tee >(get_1 ${col1}) \
| tee >(get_3 ${col3}) \
| get_5 ${col5} \
|| { >&2 echo "cat failed" && cleanup && exit 1; } &
fi
>&2 echo "before paste"
paste ${col1} ${col3} ${col5}
>&2 echo "after paste"
cleanup
exit 0
stdinからデータを読み取ると、次のようになります。
$ cat data.txt | ./test_fifos.sh
else
before paste
get_3
get_5
get_1
after paste
cleanup
したがって、これはelse
分岐が実行されたことを意味します。
答え1
&
バックグラウンドでコマンドを実行する際の問題は、シェルがコマンドへの標準入力を自動的に閉じるということです。したがって、cat -
ファイルの終わりをすぐに読みます。たとえば、回避策としてファイル記述子0を3にコピーした後、次のようになります。
...
else exec 3<&0
cat - <&3 \
| tee >(get_1 ${col1}) \
...