在腳本中使用 cURL 發布數據
我正在嘗試編寫一個簡單的替代腳本來將文件上傳到transfer.sh服務。網站上的一個範例提到了一種在單個“會話”中上傳多個文件的方法:
$ 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"
is的輸出-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
xsel --clipboard
使用或xclip
在 Linux 和pbcopy
OS X上將函式的輸出通過管道傳輸到剪貼板可能是一個好主意。@Jay 提供的解決方案也非常好用:
transfer() { printf -- "-F filedata=@%s\0" "$@" \ | xargs -0 sh -c \ 'curl --progress-bar -i "$@" https://transfer.sh | grep -i https' zerop }
避免 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 }
試試這個標準和安全的解決方案:
transfer() { printf -- "-F filedata=@%s\0" "$@" | xargs -0 sh -c 'curl --progress-bar -i "$@" https://transfer.sh | grep -i https' zerop }
"$@"
使用雙引號將使 shell 保持原始選項不變。請參閱The Open Group Base Specifications Issue 6中的2.5.2 特殊參數部分:@
擴展到位置參數,從一個開始。當擴展發生在雙引號內時,並且在執行欄位拆分(請參閱欄位拆分)時,每個位置參數都應擴展為單獨的欄位,前提是第一個參數的擴展仍應與開頭部分連接原詞(假設擴展參數嵌入一個詞中),最後一個參數的擴展仍應與原詞的最後部分連接。如果沒有位置參數,“@”的擴展將生成零欄位,即使“@”被雙引號引起來。
使用
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