1

私はこの(テスト)スクリプトを持っています:

#!/bin/bash

my_cmd_bad_ ( ) {
    cmd="$@"
    $cmd
}

my_cmd_good_ ( ) {
    "$@"
}

my_cmd_bad_  ls -l "file with space"
my_cmd_good_ ls -l "file with space"

出力は次のとおりです(ファイルは存在しません。これはこの質問のポイントではありません):

» ~/test.sh
ls: cannot access file: No such file or directory
ls: cannot access with: No such file or directory
ls: cannot access space: No such file or directory
ls: cannot access file with space: No such file or directory

最初のバージョンが期待どおりに機能しないことに驚いています。パラメーターは引用符で囲まれておらず、1 つのファイルを処理する代わりに 3 つのファイルを処理しています。なんで?

実行したいコマンドを適切に引用して保存するにはどうすればよいですか? 後で実行する必要がありますが、もうあり"$@"ません。

このテスト スクリプトを簡単に書き直していただければ幸いです。

4

4 に答える 4

2

同様の質問を参照してください: How to pass command line parameters with quotes stored in single variable?

これらのユーティリティ関数を使用して、後で実行するためにコマンドを文字列に保存します。

bash_escape() {
  # backtick indirection strictly necessary here: we use it to strip the
  # trailing newline from sed's output, which Solaris/BSD sed *always* output
  # (unlike GNU sed, which outputs "test": printf %s test | sed -e s/dummy//)
  out=`echo "$1" | sed -e s/\\'/\\''\\\\'\\'\\'/g`
  printf \'%s\' "$out"
}
append_bash_escape() {
  printf "%s " "$1"
  bash_escape "$2"
}

your_cmd_fixed_ ( ) {
  cmd="$@"
  while [ $# -gt 0 ] ; do
    cmd=`append_bash_escape "$cmd" "$1"` ; shift
  done
  $cmd
}
于 2013-03-12T12:59:54.720 に答える
1

単一のパラメーターを引用して、後で評価できます。

my_cmd_bad_ ( ) {
  j=0
  for i in "$@"; do
    cmd["$j"]=\"$"$i"\"
    j=$(( $j + 1 ))
   done;
  eval ${cmd[*]}
}
于 2013-03-12T14:06:23.543 に答える
1

スペースで区切られた 3 つの文字列「ls」、「-l」、および「file with space」を結合して、1 つのスペースで区切られた文字列にしますcmd。どのスペースが最初に (「スペースのあるファイル」で) 引用され、どのスペースが への割り当て中に導入されたかを知る方法はありませんcmd

通常、コマンド ラインを 1 つの文字列にまとめようとするのは得策ではありません。関数を使用するか、実際のコマンドを分離して引数を に残します$@

コマンドを次のように書き換えます。

my_cmd_bad_ () {
    cmd=$1; shift
    $cmd "$@"
}
于 2013-03-12T12:50:55.707 に答える
0

http://mywiki.wooledge.org/BashFAQ/050を参照してください。

ほとんどの場合、2 番目のバージョンが非常に好まれることに注意してください。唯一の例外は、何か特別なことをする必要がある場合です。たとえば、割り当て、リダイレクト、または複合コマンドをパラメーター リストにバンドルすることはできません。

引用の問題を処理する正しい方法には、標準外の機能が必要です。テンプレートを含む半現実的な例:

function myWrapper {
    typeset x IFS=$' \t\n'
    { eval "$(</dev/fd/0)"; } <<-EOF
    for x in $(printf '%q ' "$@"); do
        echo "\$x"
    done
EOF
}

myWrapper 'foo bar' $'baz\nbork'

ここで何が起こっているのかを正確に理解し、これを行う正当な理由があることを確認してください。副作用が引数に影響を与えないようにする必要があります。この特定の例は、すべてがハードコーディングされているため、事前に正しくエスケープし、必要に応じて引用された引数を展開できるため、あまり良い使用例を示していません。

于 2013-03-12T13:24:17.147 に答える