스크립트에서 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 원어의 마지막 부분과 연결되어야 합니다. 위치 인수가 없으면 "@"을 큰따옴표로 묶은 경우에도 "@"을 확장하면 0개의 필드가 생성됩니다.

이 방법을 사용하는 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 토큰화를 피하는 한 가지 방법은 배열을 사용하여 탈출하지 않고 각 인수를 전달하는 것입니다.

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
}

관련 정보