サブシェルのbash -cでEOF解析エラーが発生する

サブシェルのbash -cでEOF解析エラーが発生する

次のスクリプトが期待どおりに機能するのはなぜですか(印刷hello

#!/bin/bash

foo=$(bash -c 'echo hello')
echo $foo

そしてこのスクリプトは:

#!/bin/bash

cmd="bash -c 'echo hello'"
foo=$($cmd)
echo $foo

次のエラーが発生します。

hello': -c: line 0: unexpected EOF while looking for matching `''
hello': -c: line 1: syntax error: unexpected end of file

答え1

存在する、

cmd="bash -c 'echo hello'"
$cmd

あなたが実行しているのはbash -c 'echo hello'コマンドではなく$cmd単純なコマンドです。

引用解除は、$cmdSplit + glob演算子を呼び出すことを意味します。ここでは、デフォルト値を使用して$IFSの内容を、、に$cmd分割します。したがって、次のように入力したように、この4つのパラメータを使用して実行しています。bash-c'echohello'bash

bash -c "'echo" "hello'"

コード'echoに閉じる引用符がありません(パラメータがこのインラインスクリプトhello'に含まれています)。$0

$cmdシェルコードの内容を評価したい場合は、

eval "$cmd"

だから:

cmd="bash -c 'echo hello'"
foo=$(eval "$cmd")
echo "$foo"

Split+glob 演算子を別の方法で使用することもできます。

cmd='bash,-c,echo hello'
IFS=, # split on comma
set -f # disable glob
foo=$($cmd)
echo "$foo"

答え2

内部で実行される内容を見てみましょう$($cmd)

$ cmd="bash -c 'echo hello'"
$ foo=$(printf '<%s>' $cmd)
$ echo "$foo"
<bash> <-c> <'echo> <hello'>

ご覧のとおり、実行されたコマンドラインは次のとおりです。

$ foo=$( "bash" "-c" "'echo" "hello'")

式の一方には、実行するコマンド"'echo"で解析される一重引用符があり、bash -c閉じる一重引用符が欠落していることを(正しく)報告します。`''

1つの解決策は、evalを使用してコマンドの正しい解析を容易にすることです。

$ foo=$(eval "printf '<%s>' $cmd"); echo "$foo"
<bash><-c><echo hello>

これは働きます:

$ foo=$(eval "$cmd"); echo "$foo"
hello

しかし、正しい考えは次のとおりです。「変数はデータを保存し、関数はコードを保存します」

$ cmd(){ bash -c 'echo hello'; }
$ foo=$(cmd); echo "$foo"
hello

関連情報