
私は、bash (GNU bash、バージョン 4.4.20(1) リリース (i686-pc-linux-gnu)) のシェル拡張を理解しようとしています。
インタラクティブなbashシェルに入力する
x='$(id)'
$x
$(echo $x)
最後の2行のいずれかに次のようなエラーが出ると予想していました。
bash: uid=xxx(user): command not found
しかし
bash: $(id): command not found
。
ここでコマンド置換が行われない理由がわかりません。変数の展開後に実現されるべきではないでしょうか? 私の推測では、ここで説明されているシェル操作に関係していると思います。https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Operation
誰かこの動作を説明できますか?
私は、bash の拡張をより正確に理解することに興味があるだけです。私の質問では、実際のスクリプトを実行することには興味がありません。
答え1
$(…)
はコマンド置換です (「プロセス置換」は<(…)
など)。変数置換とコマンド置換は、文字列の左から右へ同じパスで発生します。これらの置換の結果で発生するのは、単語の分割とグロブのみです。
したがって、は5 文字の文字列 にx='$(id)'
設定されます。次に、 を実行するために、シェルは を値 に置き換えます。これには空白やグロブ文字が含まれていないため、コマンド名として扱われます。x
$(id)
$x
$x
$(id)
以下と対比:
x='@(id)'
shopt -s extglob
echo /none/$x /usr/bin/$x
ファイルが/none/id
存在しないが、/usr/bin/id
存在すると仮定すると、echo
コマンドは 3 つの単語に展開されます: echo
(当然)、/none/@(id)
(glob パターンは/none/@(id)
何も一致しないため、変更されません)、/usr/bin/id
(glob パターンは/usr/bin/@(id)
1 つのファイルに一致するため、1 要素の一致リストに置き換えられます)。
bashマニュアルでは、関連する文章はシェル拡張セクション。
展開の順序は、中括弧展開、チルダ展開、パラメータと変数の展開、算術展開、コマンド置換(左から右に実行)、単語分割、ファイル名展開です。
2 つのセミコロンの間にあるものはすべて 1 つのパスです。各パスは、前のパスの結果に基づいて動作します。
1つの文(上記で引用したような複雑な文でも)では、すべてを説明できないことに注意してください。シェルのセマンティクスは複雑です。どのシェルのマニュアルにも、すべてのコーナーケースの詳細が記載されているとは思えません。POSIX仕様より正式ですが、bash 固有の拡張機能はカバーされておらず、いくつかの非常に奇妙なケースは未定義のままになっています。
答え2
それは引用です。一重引用符 ( '
) はリテラル文字列を定義し、補間やエスケープは発生しません。二重引用符 ( "
) は補間とエスケープを可能にします。
次に例を示します。
$ x='$(id)'
$ echo 'The variable x contains the value \"$x\"'
The variable x contains the value \"$x\"
$ echo "The variable x contains the value \"$x\""
The variable x contains the value "$(id)"
$ x="$(id)"
$ echo "The variable x contains the value \"$x\""
The variable x contains the value "uid=1000(myusername)..."
以下は、一重引用符と二重引用符に基づく補間とエスケープの別の例です。
$ echo 'The current directory is $PWD according to the variable \"\$PWD\".'
The current directory is $PWD according to the variable \"\$PWD\".
$ echo "The current directory is $PWD according to the variable \"\$PWD\"."
The current directory is /tmp according to the variable "$PWD".