web-dev-qa-db-ja.com

bashでは、パイプが値を設定していない後に読み取ります

編集:元のタイトルは「bashで読み取りに失敗しました」でした

Kshでは、値を分離する便利な方法としてreadを使用しています。

$ echo 1 2 3 4 5 | read a b dump
$ echo $b $a 
2 1
$

しかし、それはbashでは失敗します:

$ echo 1 2 3 4 5 | read a b dump
$ echo $b $a 

$

Manページで失敗する理由が見つかりませんでした。

23
Emmanuel

bashパイプラインの右側を実行サブシェルコンテキスト なので、変数に変更します(これはreadが行うことです)保存されません—コマンドの最後でサブシェルが死ぬと死にます。

代わりに、 プロセス置換 を使用できます。

$ read a b dump < <(echo 1 2 3 4 5)
$ echo $b $a
2 1

この場合、readはプライマリシェル内で実行され、出力生成コマンドはサブシェルで実行されます。 <(...)構文 creates サブシェルを使用して、その出力をパイプに接続します。パイプは、通常の <操作でreadの入力にリダイレクトされますreadはメインシェルで実行されたため、変数は正しく設定されています。

コメントで指摘されているように、目的が文字列を何らかの方法で変数に分割することである場合は、 here string を使用できます。

read a b dump <<<"1 2 3 4 5"

それ以外にもあると思いますが、ない場合はこれがより良い選択肢です。

29
Michael Homer

bashPOSIXbashの両方の動作を許可するため、これはkshのバグではありません。

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_12

さらに、マルチコマンドパイプラインの各コマンドはサブシェル環境にあります。ただし、拡張機能として、パイプライン内の一部またはすべてのコマンドを現在の環境で実行できます。他のすべてのコマンドは、現在のシェル環境で実行されます。

ただし、bash 4.2以降では、非インタラクティブスクリプトでlastpipeオプションを設定して、期待される結果を得ることができます。例:

#!/bin/bash

echo 1 2 3 4 5 | read a b dump
echo before: $b $a 
shopt -s lastpipe
echo 1 2 3 4 5 | read a b dump
echo after: $b $a 

出力:

before:
after: 2 1
19
jlliagre