17

私はここや他のすべての場所でbashの引用符について読んでいますが、この問題を解決する助けはありませんでした。

問題は、ループでバックアップを実行するための小さなスクリプトがあるということです。

使用しない場合は、の変数にeval問題があります。$OPTIONSrsync

しかし、私が使用するeval場合、問題は変数に行きます$CURRENT_DIR...

rsyncは次のメッセージを返します:'予期しないローカル引数:/ path / with'

変数を引用するあらゆる方法を試しました$CURRENT_DIR

CURRENT_DIR="/path/with spaces/backup"
DIR="dir_by_project"
f=":/home/project_in_server"
OPTIONS="-avr --exclude 'public_html/cms/cache/**' --exclude 'public_html/cms/components/libraries/cmslib/cache/**' --delete"
eval rsync --delete-excluded -i $OPTIONS  root@example.com$f $CURRENT_DIR/xxx/$DIR/files

$CURRENT_DIRスペースに起因する問題なしに変数を使用できる方法はありますか?

4

7 に答える 7

20
eval rsync --delete-excluded -i $OPTIONS  root@example.com$f "\"$CURRENT_DIR/xxx/$DIR/files\""

command "some thing"1つの引数でコマンドを実行しますsome thing。引用符はシェルによって解析され、コマンドの実行時に引数が配列として設定されます。コマンドは、引数を引用符なしの何かとして認識します。

evalコマンドは、引数をシェルに入力されたかのように多かれ少なかれ扱います。したがって、の場合eval command "some thing"、bashは2つの引数で実行evalされます:commandおよびsome thing(bashが引数の配列を設定している間、引用符が使用されます)。したがって、evalはcommand some thing、シェルに入力したかのように機能しますが、これは必要なことではありません。

私がしたことは、単に引用符をエスケープして、bashが引用符を含む文字通り「何か」をevalに渡すようにすることでした。evalは、入力したかのように機能しますcommand "some thing"

私のコマンドの外側の引用符は厳密には必須ではなく、単なる習慣です。あなたも同様に使用することができます:

eval rsync --delete-excluded -i $OPTIONS  root@example.com$f \"$CURRENT_DIR/xxx/$DIR/files\"
于 2011-03-10T00:10:46.520 に答える
8

evalの使用は危険であり、可能な限り避ける必要があります。この場合の主な問題は、OPTIONSを複数の単語を含むものとして定義しようとしていることであり、bash変数はこれをうまく処理しません。解決策があります。単純な変数ではなく、配列にOPTIONSを配置します(スペースが単語の区切り文字として扱われないように、すべての変数参照を二重引用符で囲みます)。

CURRENT_DIR="/path/with spaces/backup"
DIR="dir_by_project"
f=":/home/project_in_server"
OPTIONS=(-avr --exclude 'public_html/cms/cache/**' --exclude 'public_html/cms/components/libraries/cmslib/cache/**' --delete)
rsync --delete-excluded -i "${OPTIONS[@]}"  "root@example.com$f" "$CURRENT_DIR/xxx/$DIR/files"
于 2011-03-10T07:44:12.073 に答える
4

一般的な再利用可能なソリューション

物事を正しく引用する方法を理解することは重要ですが、使いやすさとスリップアップを防ぐために、私は次の関数を使用することを好みます。

以下は、配列の各要素を引用符で囲むことにより、引数にスペースを保持します。

function token_quote {
  local quoted=()
  for token; do
    quoted+=( "$(printf '%q' "$token")" )
  done
  printf '%s\n' "${quoted[*]}"
}

使用例:

$ token_quote token 'single token' token
token single\ token token

single token上記では、のスペースがとして引用されていることに注意してください\

$ set $(token_quote token 'single token' token)
$ eval printf '%s\\n' "$@"
token
single token
token
$

これは、トークンが実際に別々に保持されていることを示しています。


信頼できないユーザー入力がある場合:

% input="Trying to hack you; date"

評価するコマンドを作成します。

% cmd=(echo "User gave:" "$input")

一見正しい引用でそれを評価します:

% eval "$(echo "${cmd[@]}")"
User gave: Trying to hack you
Thu Sep 27 20:41:31 +07 2018

ハッキングされたことに注意してください。date文字通り印刷されるのではなく、実行されました。

代わりにtoken_quote()

% eval "$(token_quote "${cmd[@]}")"
User gave: Trying to hack you; date
%

eval悪ではありません-それはただ誤解されています:)

于 2018-09-29T05:45:08.113 に答える
3

ゴードンに同意します

この場合、evalは必要ありません(変数から変数名を作成したり、その場で式を作成したりすることはありません)。

そして、保存したいスペースがある可能性があるすべての変数参照を二重引用符で囲みます

しかし、もう1つの良い習慣は、常に{}..で変数を参照することです。

  "${CURRENT_DIR}" 

それ以外の

  $CURRENT_DIR

これにより、名前のあいまいさがなくなります

于 2011-03-10T08:31:20.743 に答える
0

おそらくypuがすでにそれを使用していることは知っていますが、一重引用符はどうでしょうか。(このタイプ'')?

于 2011-03-09T23:51:38.460 に答える
-1

CURRENT_DIR="/path/with\ spaces/backup"これが機能しない場合は、スペースをエスケープする必要があります。次に、二重の円記号を入れます。CURRENT_DIR="/path/with\\ spaces/backup"

于 2011-03-09T23:54:32.617 に答える