スクリプトでcURLを使用してデータを公開する

スクリプトでcURLを使用してデータを公開する

ファイルをアップロードするための簡単な代替スクリプトを作成しようとしています。ファイル転送提供する。ウェブサイトの例では、単一の「セッション」から複数のファイルをアップロードする方法について説明します。

$ curl -i -F filedata=@/tmp/hello.txt \
  -F filedata=@/tmp/hello2.txt https://transfer.sh/

私は必要な数のパラメータ(ファイル)を許可し、この方法でcURLに渡すことができる関数を作成しようとしています。機能は次のとおりです。

transfer() {
    build() {
        for file in $@
        do
            printf "-F filedata=@%q " $file
        done
    }

    curl --progress-bar -i \
        $(build $@) https://transfer.sh | grep https
}

ファイル名にスペースがない場合、関数は期待どおりに機能します。出力結果printf "-f filedata=@%q " "hello 1.txt"-F filedata=@test\ 1.txt特殊文字が正しくエスケープされると期待します。ただし、スペースを含むファイル名で関数を呼び出す場合:

$ transfer hello\ 1.txt

cURLがエスケープを解釈できないようでエラーを報告します。

curl: (26) couldn't open file "test\"

また、コマンドの一部を引用してみましたprintf "-F filedata=@\"%s\" " "test 1.txt"-F filedata=@"test 1.txt"この場合、cURLは同じエラーを返しますcurl: (26) couldn't open file ""test"。引用符にはまったく気にしないようです。

この動作の原因が何であるかよくわかりません。スペースを含むファイル名も処理するようにこの関数をどのように変更しますか?


編集/解決策

@meuhが説明したように、この問題は配列を使用して解決できます。両方に適したソリューションは次のとおりbashですzsh

transfer () {
    if [[ "$#" -eq 0 ]]; then
        echo "No arguments specified."
        return 1
    fi

    local -a args
    args=()
    for file in "$@"
    do
        args+=("-F filedata=@$file")
    done

    curl --progress-bar -i "${args[@]}" https://transfer.sh | grep https
}

zsh合計の出力は次bashのとおりです。

$ ls
test space.txt    test'special.txt
$ transfer test\ space.txt test\'special.txt
######################################################################## 100.0%
https://transfer.sh/z5R7y/test-space.txt
https://transfer.sh/z5R7y/testspecial.txt
$ transfer *
######################################################################## 100.0%
https://transfer.sh/4GDQC/test-space.txt
https://transfer.sh/4GDQC/testspecial.txt

LinuxとOS Xでは、xsel --clipboard関数の出力をクリップボードとして使用またはパイプすることをお勧めします。xclippbcopy


@Jayが提供するソリューションも非常にうまく機能します。

transfer() {
  printf -- "-F filedata=@%s\0" "$@" \
    | xargs -0 sh -c \ 
    'curl --progress-bar -i "$@" https://transfer.sh | grep -i https' zerop
}

答え1

次の標準的で安全なソリューションをお試しください。

transfer() {
  printf -- "-F filedata=@%s\0" "$@" | xargs -0 sh -c 'curl --progress-bar -i "$@" https://transfer.sh | grep -i https' zerop
}

"$@"二重引用符を追加すると、シェルは元のオプションを変更せずに残ります。バラより2.5.2 特殊パラメータ部分的にOpen Group 基本仕様 6号:

@

1から始まる位置パラメータに展開されます。拡張が発生した場合二重引用符の中とフィールドの分割(参照)フィールド分割When 原語の最後の部分に関連付ける必要があります。位置引数がない場合は、「@」を二重引用符で囲んでも「@」を展開するとゼロ個のフィールドが生成されます。

この方法の使用は、printfオプションを処理する標準的な方法です。これをテストして、結果がオプションの数-F filedata=@だけ文字列を生成することを確認できます。

名前に特殊文字が含まれる2つのファイルでテストされました。

$ ls -b
f\ rst  s'cond

$ transfer() { printf -- "-F filedata=@%s\0" "$@" | xargs -0 sh -c 'curl --progress-bar -i "$@" https://transfer.sh | grep -i https' zerop ;}

$ transfer *
######################################################################## 100.0%
https://transfer.sh/fnzuh/f-rst
https://transfer.sh/fnzuh/scond

答え2

Bashトークン化を回避する1つの方法は、配列を使用してエスケープせずに各引数を渡すことです。

push(){ args[${#args[*]}]="$1"; }
build() {
    args=()
    for file
    do  push "-F"
        push "filedata=@$file"
    done
}
build "$@"
curl --progress-bar -i "${args[@]}" https://transfer.sh | grep https

このbuild関数は配列を作成し、配列のargs末尾pushに新しい値を追加します。単にcurl配列を使用してください。


最初の部分は単純化またはpush簡単に作成できます。args+=("$1")これを削除してbuild次に変更できます。

build() {
    args=()
    for file
    do  args+=("-F" "filedata=@$file")
    done
}

関連情報