実行するコマンドを文字列として保存する必要があるスクリプトを作成しようとしています。問題の文字列には引用符が含まれている必要があり、実行しようとすると bash によって追加の引用符文字が追加され、場合によってはコマンドが期待どおりに実行されないことがあります。
以下にサンプル スクリプトを示します。このサンプル スクリプトで実行されるコマンドはexample
、明らかに何も行わず、単に と表示されます。ただし、 の行に をcommand not found
追加して、実行される正確なコマンドが出力されるようにしたので、スクリプトを実行して、私が何を言っているのかを確認することができます。-x
#!/bin/bash
例:
#!/bin/bash -x
#command typed explicitly
example -options "-i filename"
#command stored in string first
commandstring='example -options "-i filename"'
echo "running command: ${commandstring}"
${commandstring}
このスクリプトを実行した場合の出力は次のようになります (2 つの「コマンドが見つかりません」エラーは無視します)。
+ example -options '-i filename'
+ commandstring='example -options "-i filename"'
+ echo 'running command: example -options "-i filename"'
running command: example -options "-i filename"
+ example -options '"-i' 'filename"'
したがって、最初の行は、コマンドライン パラメータを指定すると期待どおりに実行されることがわかります。
-i filename
しかし、echo
コマンドは文字列を完璧に実行できる方法で出力しますが、文字列がコマンドラインに置かれると、文字列は変化し、渡されるパラメータは
'"-i' 'ファイル名"'
これには追加の引用符文字が含まれており、実際のスクリプトで使用している実際のコマンドが失敗する原因となっています。
これを防ぐ方法はありますか?
答え1
を使用している場合bash
、コマンドを正確に保存する最も簡単な方法は、それを配列に入れることです。実行したいコマンドが次の場合:
example -options "-i filename"
次のように配列変数に保存できます。
commandline=(example -options "-i filename")
次に、二重引用符内の配列を @ 展開することで、保存したコマンドをそのまま実行できます。
"${commandline[@]}"
ここで知っておくべき重要なことは、シェルは引用符文字 ( "'\
) を、コマンドラインに直接入力した場合と、 のように変数展開内で見つけた場合とで異なる方法で扱うということです${commandstring}
。コマンドラインでは、引用符文字には特別な引用機能があります。パラメータ展開内では、引用符文字は通常の非特殊文字です。したがって、 は、"-i filename"
コマンドラインに入力すると として解析される単一の単語です-i filename
が、変数内の同じ文字は および"-i
という単語に展開されますfilename"
。
バッシュFAQ50このトピックについてさらに詳細に説明します。