文字列として実行するコマンドを保存する必要があるスクリプトを作成しようとしています。問題の文字列には引用符を含める必要があります。これを実行しようとすると、bashは追加の引用符を追加します。これにより、コマンドが期待どおりに実行されないことがあります。
以下はサンプルスクリプトです。このスクリプト例では、runコマンドは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")
その後、二重引用符で配列を@expandして、保存されたコマンドを実行できます。
"${commandline[@]}"
ここで知っておくべき重要な点は、"'\
コマンドラインに直接入力すると、シェルが変数拡張と同じ方法で引用符文字()を処理することです(たとえば、コマンドラインの引用符には${commandstring}
特別な引用符があります。通常の文字であるパラメータ拡張は、"-i filename"
コマンドラインに入力すると単一の単語に解析されますが、変数の同じ文字はおよび-i filename
単語に拡張されます。"-i
filename"
バッシュFAQ 50このトピックはさらに詳しく説明します。