Estou tentando escrever um script alternativo simples para o upload de arquivos para o serviço transfer.sh . Um dos exemplos no site menciona uma maneira de fazer upload de vários arquivos em uma única "sessão":
$ curl -i -F filedata=@/tmp/hello.txt \
-F filedata=@/tmp/hello2.txt https://transfer.sh/
Eu estou tentando fazer uma função que levaria qualquer número de argumentos (arquivos) e passá-los para cURL dessa maneira. A função é a seguinte:
transfer() {
build() {
for file in $@
do
printf "-F filedata=@%q " $file
done
}
curl --progress-bar -i \
$(build $@) https://transfer.sh | grep https
}
A função funciona conforme o esperado, desde que não haja espaços nos nomes dos arquivos.
A saída de printf "-f filedata=@%q " "hello 1.txt"
é -F filedata=@test\ 1.txt
, então esperei que os caracteres especiais fossem escapados corretamente. No entanto, quando a função é chamada com um nome de arquivo que inclui espaços:
$ transfer hello\ 1.txt
cURL não parece interpretar as fugas e relata um erro:
curl: (26) couldn't open file "test\"
Eu também tentei citar partes do comando, por exemplo printf "-F filedata=@\"%s\" " "test 1.txt"
, que produz -F filedata=@"test 1.txt"
.
Nesse caso, cURL retorna o mesmo erro: curl: (26) couldn't open file ""test"
. Parece que não se importa com as citações.
Não tenho certeza do que causa esse comportamento. Como eu poderia corrigir a função para também trabalhar com nomes de arquivos que incluem espaço em branco?
Editar / Solução
Foi possível resolver o problema usando uma matriz, conforme explicado por @meuh. Uma solução que funciona em bash
e 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
}
A saída em zsh
e 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
Pode ser uma boa ideia enviar a saída da função para a área de transferência com xsel --clipboard
ou xclip
no Linux e pbcopy
no OS X.
A solução fornecida pelo @Jay também funciona perfeitamente:
transfer() {
printf -- "-F filedata=@%s$ curl -i -F filedata=@/tmp/hello.txt \
-F filedata=@/tmp/hello2.txt https://transfer.sh/
" "$@" \
| xargs -0 sh -c \
'curl --progress-bar -i "$@" https://transfer.sh | grep -i https' zerop
}