Bourne Shellで複数行を読む

Bourne Shellで複数行を読む

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 つの変数firstlinesum secondline(両方を読み取った後) が含まれますが、サブシェルが終了すると、両方の変数が削除され、削除されます。

これはPOSIXshbash

(4.2+)では、bashシェルオプションを設定することでこの問題を解決できますlastpipebashマニュアルから:

パイプラインの各コマンドは、別々のプロセス(つまりサブシェルで)で実行されます。サブシェル環境の説明については、コマンド実行環境を参照してください。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するのではなく、両方の呼び出しを直接使用して複合コマンドにリダイレクトすることもできます。bashcatread

{ read firstline; read secondline; } <myfile

ちなみに、お使いのコンピュータには実際の歴史的なBourneシェルがない可能性があります(Solaris 11以前のSolarisシステムではない限り)。私はあなたが最新のPOSIXshシェルに言及していると仮定します。

おすすめ記事