これが「読み取り中」でターミナルで機能するのにシェルスクリプトでは機能しないのはなぜですか?


8

ルートウィンドウのタイトルを設定して適用される情報テキストをWMバーに入力しているときに、この興味深い問題に遭遇しました。 xsetroot -name "clever words"

この目的のために、運命を印刷することはターミナルでうまく機能します:

fortune -s | while read -r; do xsetroot -name "$REPLY"; done

しかし、シェルスクリプトから実行すると、同じことが失敗します。

#!/bin/sh
cat /tmp/afile | while read; do echo "$REPLY"; done

生成:

$ sh afilereader
afilereader:2:read:arg count

もちろん、これは私たちの運命の結果を変数に割り当て、次にその変数でxsetrootを使用することによって修正されます。しかしこれがスクリプトで機能しない理由を理解したいと思います。

パイプラインのいずれかの側の各コマンドはそれ自体のサブシェル内で実行されることを理解していますが、ローカライズされた変数がwhile読み取りループにどのように影響するかを確認できません。または、ループの反復間でも​​変数がスコープ外ですか?

何が欠けていますか?

更新:使用したshIはダッシュにリンクされていますが、これはPOSIX準拠にされる過程にあります。より由緒あるものを使用してbashこれを解決しました。


1
ここでのダッシュの振る舞いは、POSIX準拠に達していないことを明示していません。POSIXはする必要はありませんread:変数なしで呼び出し可能であることpubs.opengroup.org/onlinepubs/9699919799/utilities/read.html
dubiousjim

回答:


10

あなたは最初の例をで実行しているように見えbash、2番目の例はが指しているもの/bin/shで実行しています。これは、入力を入れたい変数を指定する引数を渡す必要があるPOSIXシェルです。シバンを変更して#!/bin/bashこれを修正する必要があります。


@Chrisの良い観察!うまくいきます。shとの違いについて少し読んでみましょうbash
反転

確かに異常!/bin/shbashに再リンクすることはできますが、あいまいさを避けるために、今後はbashを直接使用するだけだと思います。ありがとう:)
反転

多くの場合、対話型シェルは、出力のバッファリングにおいてシェルスクリプトとは異なります。プロセス間パイプからの読み取りは、出力を生成するコマンドが非対話的に実行されたときに書き込みをバッファリングする場合、あらゆる種類の奇妙なタイミング動作を引き起こす可能性があります。
JesseM 2017年

5

sh構文では、

IFS= read -r REPLY

ksh、bash、zshなどの一部のシェルではread、変数名なしで呼び出すことができますが、動作はシェルによって異なります。たとえばの出力を参照してください

printf 'te\ st\\\na ' | "$shell" -c 'read; printf "%s\n" "<$REPLY>"'

bash、zsh、pdksh、ksh93のすべてで異なる


@Stephaneのおかげで、私が使用していたシェルが変数名を認識できなかったのは当然のことです。
反転
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.