Fish が生成した Rsync コマンドが予期しない効果をもたらす

Fish が生成した Rsync コマンドが予期しない効果をもたらす

私は fish シェルを使用しており、パラメータをすべて設定した rsync コマンドを生成するヘルパー関数があります。最終的な rsync コマンドは次のようになります (コマンドは 1 行ですが、読みやすいように複数行にしました)。

rsync -razs -e="ssh -p2222" --update --progress \ 
    --exclude=".*" --exclude="__pycache__" 
    --delete --dry-run \
    $source_dir $dest_dir

ターミナルからは正常に動作しますが、ヘルパー関数を使用しようとすると、「exclude」パラメータが効かないようです。生成されたコマンドは、ssh コマンドが引用符で囲まれていないことを除いてまったく同じに見えます。ただし、サーバーに接続できるため、これは問題ではないようです。前述したように、唯一の問題は、exclude が無視されることです。

生成されたコマンドは次のようになります。

rsync -razs -e=ssh -p2222 --update --progress \
    --exclude=".*" --exclude="__pycache__" \
    --delete --dry-run \
    /home/some_folder user@host:/home/

何か案が?

関数は次のようになります。

function ssync -d "rsync through ssh tunnel" 

    set origin $argv[1]
    set destination $argv[2]
    set exclude ".*" "__pycache__"

    set ssh_config "ssh -p2222"
    set params -razs -e="$ssh_config" --update --progress --exclude=\"$exclude\"

    if test (count $argv) -gt 2
        set option $argv[3]
        set params $params --delete
        if [ $option = "--delete" ]
            set_color red; echo "Warning: Unsafe run!";
            read -l -P "Confirm? [y/N] " yesno;
            switch $yesno
                case '' N n
                    echo "Sync canceled by user"
                    return 0
                case Y y
                    echo "Proceeding..."
            end
        else
            set params $params --dry-run
        end
    end

    echo "rsync $params $origin $destination"
    rsync $params $origin $destination;
end

[編集]: Glenn さんの回答のおかげで、関数内で引用符リテラルを使用していることが問題の原因であることがわかりました。ただし、引用符リテラルには、 のようにスペースで区切られた複数の値を持つ引数を のように区切るという非常に便利な効果がありますarg1 arg2--exclude="arg1" --exclude="arg2"不便さを伴わずに利点を得る方法はありますか?

答え1

引用符文字を追加しています

... --exclude=\"$exclude\"

これにより、rsync はファイル名に引用符が含まれるファイルを検索するようになります。

単語を引用符で囲むだけでいい

... "--exclude=$exclude"

引用符の目的は、シェルにコマンドをトークン化するように指示することであることを覚えておいてください。あなた実際の引用符文字は、シェルが実際にコマンドを実行する前に削除されます。


はい、リスト$exclude 内の項目。代わりに中括弧を使用してください: demo:

$ set exclude ".*" file1 file2
$ set params --some stuff --other stuff --exclude={$exclude}
$ echo $params
--some stuff --other stuff --exclude=.* --exclude=file1 --exclude=file2

$excludeが空の場合、パラメータにはいいえ--exclude オプション:

$ set -e exclude
$ set params --some stuff --other stuff --exclude={$exclude}
$ echo $params
--some stuff --other stuff

関連情報