ダッシュ:パイプから変数を読み取る

ダッシュ:パイプから変数を読み取る

bashまたは、zsh次の構文を使用してパイプから変数を読み取ることができます。

echo AAA BBB | read X Y ; echo $X

これは印刷されますAAA

で同じアプローチが機能しないのはなぜですか/bin/sh

使っています/bin/sh- >/bin/dash スプリントDebian で

答え1

なぜ同じ方法が '/bin/sh'で動作しないのですか?

パイプライン内の各コマンドはサブシェルで実行されるため、パイプラインから変数を割り当てると期待どおりにsh機能しません。bash実際、コマンドは実際に働くが宣言されXましたがY、パイプラインの外では使用できません。

以下が機能します。

echo AAA BBB | { read X Y ; echo $X; }

しかし、あなたの場合は:

この試み、

read X Y <<< "AAA BBB"

または

read X Y < <(echo "AAA BBB")

便利なリンク:

答え2

Bashまたはzshでは、次の構文を使用してパイプから変数を読み取ることができます。

echo AAA BBB | read X Y ; echo $X

いいえ、できません。デフォルトでは Bash では使用できません。

$ ./bash5.0-alpha -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X=\"$X\""'
Bash=5.0.0(1)-alpha X=""
$ bash -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X=\"$X\""'
Bash=4.4.12(1)-release X=""

Bashは別のサブシェル環境でパイプライン内のすべてのコマンドを実行するため、シェル変数に対する変更はパイプラインの外には表示されません。ダッシュもここに似ています。

Zsh と ksh (AT&T 実装pdkshまたはその派生物ではない) は、デフォルトのシェル環境でパイプラインの最後のコマンドを実行するため、次のように動作します。

$ zsh -c 'echo AAA BBB | read X Y ; echo "Zsh=$ZSH_VERSION X=\"$X\""'
Zsh=5.3.1 X="AAA"

Bash では、shopt -s lastpipeksh と zsh が何をするかを実行できます (ただし、非対話型シェルのみ)。

$ bash -O lastpipe -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X=\"$X\""'
Bash=4.4.12(1)-release X="AAA"

しかし、ダッシュにはそのような選択肢がないと思います。

Bashではパイプの代わりにプロセス置換を使用することもできますが、これはDashでもオプションではありません。


解決策は、ループの右側を複合文または関数として作成し、パイプから読み取った値を読み取ったのと同じコンテキストで使用することです。

$ dash -c 'echo AAA BBB | { read X Y ; echo "X=\"$X\""; } '
X="AAA"
$ dash -c 'f() { read X Y ; echo "X=\"$X\""; }; echo AAA BBB | f'
X="AAA"

またはこちらの記事を使用してください。

read X Y << EOF
$(echo AAA BBB)
EOF

答え3

いいえ、XとY(セミコロンの後ろ)は設定されません。

echo AAA BBB | read X Y ; echo $X
$ bash -c 'echo AAA BBB | read X Y ; echo "<$X>"'
<>

ダッシュでも同じことが起こります。

ダッシュボードで機能させるには、以前のソリューション(ここではドキュメント)を使用する必要があります。

$ read X Y <<_EOT_
> AAA BBB
> _EOT_
$ echo "<$X>"
<AAA>

シェルを試すためのコマンド(残念ながら改行文字は削除できません(1行文字なし)):

$ bash -c 'read X Y <<_EOT_
AAA BBB
_EOT_
echo "<$X>" '
<AAA>

これは、ダッシュ、zsh、ksh、その他多くのツールでまったく同じように機能します。

$ dash -c 'read X Y <<_EOT_
AAA BBB
_EOT_
echo "<$X>" '
<AAA>

新しい選択肢(ダッシュでは機能しません)は次here-docのとおりです。

  1. 文字列は次のとおりです(bash、ksh、zsh用)。

    $ bash -c 'read X Y <<<"AAA BBB"; echo "<$X>" '
    <AAA>
    
  2. プロセスの交換(bash、ksh、zshに適用可能):

    $ bash -c 'read X Y < <(echo AAA BBB) ; echo "<$X>" '
    <AAA>
    

値を印刷してダッシュで作業するもう1つの選択肢は次のとおりです。

  1. グループコマンド:

    $ dash -c 'echo "AAA BBB" | { read X Y ; echo "<$X>"; }; echo "<$X>" '
    <AAA>
    <>
    

    最後の解決策は、bashで設定された変数lastpipe(対話式ではない)またはksh / zshのデフォルト設定を維持するように設定できます。

    $ bash -c 'shopt -s lastpipe;echo "AAA BBB"|{ read X Y;echo "1<$X>"; };echo "2<$X>"'
    1<AAA>
    2<AAA>
    
    $ ksh -c 'echo "AAA BBB"|{ read X Y;echo "1<$X>"; };echo "2<$X>"'
    1<AAA>
    2<AAA>
    
    $ zsh -c 'echo "AAA BBB"|{ read X Y;echo "1<$X>"; }; echo "2<$X>"'
    1<AAA>
    2<AAA>
    

答え4

パイプのプロセス固有変数の割り当てに注意してください。 POSIX 標準は特定の動作を必要としません。

最新のシェルksh93と最新バージョンのシェルは、プライマリBourne Shellシェルをパイプライン上の2つのプロセスの親プロセスにし、一番右のプロセスが組み込みコマンドの場合、そのコマンドはデフォルトシェルでも実行されます。

別のバリエーションは上記の方法を使用しますが、常に他のプロセスで一番右のコマンドを実行することです。

以前のバージョンは、元のBourne Shellがどのように機能するかです。シェルフォーク、フォークプロセスはパイプから他のすべてのプロセスを生成し、最終的に最も右側のプロセスに切り替えます。

最後のバージョンは他のバージョンよりはるかに少ないコードが必要ですが、遅くなります。コードサイズの問題により、1976年に使用されました。

最初のバリアントは最も高速ですが、他のバリアントよりも多くのコードが必要ですが、元のシェルプロセスで変数割り当てを実行する唯一のバリエーションであるため、変更された変数の値はデフォルトのシェルに存在する必要があります。

関連情報