2行を2つの変数として読み込もうとしています。 Bashでは、次のようなものを使用します。
cat << EOF > myfile
line1
line2
EOF
cat myfile | {
read firstline
echo $firstline # "line1" in bash and sh
read secondline
}
echo $firstline # "line1" in bash, empty in sh
echo $secondline
ただし、Bourne Shell では、$firstline
コマンド$secondline
グループの外部では空です。 shでどうすればいいですか?
ベストアンサー1
firstline
(テストでコードをテストするときにこれを設定した可能性が高く、bash
その値は最終的に空でなければなりません。)
パイプラインを実行するとき
cat myfile | { read firstline; read secondline; }
右側はサブシェルで実行されます。{ ...; }
これはパイプラインの一部ではないからです。サブシェル環境には 2 つの変数firstline
sum secondline
(両方を読み取った後) が含まれますが、サブシェルが終了すると、両方の変数が削除され、削除されます。
これはPOSIXsh
とbash
。
(4.2+)では、bash
シェルオプションを設定することでこの問題を解決できますlastpipe
。bash
マニュアルから:
パイプラインの各コマンドは、別々のプロセス(つまりサブシェルで)で実行されます。サブシェル環境の説明については、コマンド実行環境を参照してください。
lastpipe
組み込みオプションを使用して有効にするとshopt
(以下の説明を参照shopt
)、パイプの最後の要素がシェルプロセスによって実行される可能性があります。
これはスクリプトでは機能しますが、ジョブ制御が有効な対話型シェルでは機能しません(ジョブ制御のために機能せず、対話型ではありません)。
例:
$ cat script.sh
cat << EOF > myfile
line1
line2
EOF
cat myfile | { read firstline; read secondline; }
printf 'first=%s\n' "$firstline"
printf 'second=%s\n' "$secondline"
shopt -s lastpipe
cat myfile | { read firstline; read secondline; }
printf 'first=%s\n' "$firstline"
printf 'second=%s\n' "$secondline"
$ bash script.sh
first=
second=
first=line1
second=line2
場合によっては、POSIXで完全にキャンセルしてパイプsh
するのではなく、両方の呼び出しを直接使用して複合コマンドにリダイレクトすることもできます。bash
cat
read
{ read firstline; read secondline; } <myfile
ちなみに、お使いのコンピュータには実際の歴史的なBourneシェルがない可能性があります(Solaris 11以前のSolarisシステムではない限り)。私はあなたが最新のPOSIXsh
シェルに言及していると仮定します。