arquivos
sample$1.class
sample.class
scp_test.sh
scp_test.sh
#!/bin/bash
TARGET=('sample.class' 'sample$1.class')
for dd in "${TARGET[@]}"
do
FILENAME=`basename ${dd}`
scp ${FILENAME} remote:/tmp/${dd}
done
Quando o shell é executado, sample$1.class
é substituído no sample.class
servidor remoto,
deixando apenas sample.class
.
$ ./scp_test.sh
sample.class 100% 0 0.0KB/s 00:00
sample$1.class 100% 0 0.0KB/s 00:00
$ ssh remote 'ls -l /tmp/'
total 01
sample.class
Isso só acontece quando é copiado por scp
. Cópia local usando cp
não se comporta assim.
*EDIT Como uso a versão Bash em 4.3(4.2.46), não posso usar ${dd@Q}
. Corrigi o problema usando a combinação de cotações '"${dd}"'
em vez de plain ${dd}
.
Nota preliminar
Esta resposta é principalmente sobre tradicional
scp
, ou seja, legadoscp
usando o protocolo SCP. Modernscp
do OpenSSH usa SFTP por padrão e quando estou escrevendo isso a transição tem menos de dois meses; então é bem fresco. Posso dizer que vocêscp
usa o SCP, porque se ele usasse SFTP, você não encontraria o problema em questão. Resolver esses problemas foi uma das razões pelas quais o SCP foi substituído pelo SFTP.Do changelog :
Problemas potenciais independentes de
scp
Primeiro de tudo: cite certo . Seus nomes de exemplo podem ser seguros, mesmo sem aspas, ainda escrever código robusto é uma virtude. IMO é mais fácil sempre citar do que pensar muito a cada vez se você puder fugir sem citar. Seu código com variáveis corretamente citadas ficará assim (observe que ainda não tento resolver o problema
scp
, isso será feito em um momento):(Também consertei nomes todos em maiúsculas , introduzi duplo traço no caso de você adicionar um nome de arquivo começando com um traço a
target
. Acho quebasename
não é operacional neste caso específico, mas suponho que você tenha uma razão para isso.)Se o seu
scp
SFTP usado, o código acima funcionaria (e, francamente, acho que seu código original também funcionaria com talscp
, mas apenas porque os nomes que você usou são "seguros" quando não citados).A questão com
scp
Infelizmente, o legado
scp
incorpora o nome do caminho remoto em um código de shell que deve ser interpretado por um shell remoto (compare esta minha resposta ). O shell remoto interpretará caracteres como aspas,$
etc.[
, a menos que sejam escapados ou citados quando chegarem ao shell remoto. Isso significa que localmente você precisa citar adicionalmente com o shell remoto em mente. Você precisa citar para o shell local e para o shell remoto. Isso é o que a citação significa "exigir aspas duplas de meta-caracteres do shell em nomes de arquivos".Solução
Bash pode ajudar.
"${dd@Q}"
irá expandirdd
e escapar ou citar o resultado, então após um nível adicional de interpretação (realizado pelo shell remoto no seu caso) o resultado será uma única palavra que você esperaria (como"$dd"
expandido localmente). A linha a seguir é uma correção para o legadoscp
:Todo o roteiro será:
A solução não é portátil, não funcionará em arquivos
sh
. O shebang em seu script é#!/bin/bash
desde o início, então acho que você não se importa com o código que só funciona no Bash.Notas finais
O primeiro trecho (sem
${dd@Q}
) é adequado parascp
usar SFTP (ou seja, o novo). O segundo trecho (com${dd@Q}
) é adequado parascp
usar SCP (ou seja, o legadoscp
). Não existe um código universal simples. Os novosscp
suportes-O
que fazem com que ele se comporte como o legacyscp
, mas se você usar um legacyscp
com-O
então ele falhará porque achará a opção inválida. De qualquer forma, você precisa saber se o seuscp
é novo ou antigo e ajustar seu código de shell de acordo. Por enquanto, o seuscp
é antigo (e, portanto, o problema em primeiro lugar), mas se você o atualizar, ele poderá ser substituído por um novo. O changelog já vinculado percebe a incompatibilidade:Lado "questão", um conselho amigável. Nomear seus scripts como
scp_test.sh
não é um bom hábito. Para o seuscp_test.sh
o intérprete já ébash
, nãosh
. Seu código original precisabash
e não funciona purosh
(por causa do array). Você vai renomear parascp_test.bash
? E se você portasse o script para Python? OK, eu não acho que você vai fazer isso com o script em questão, mas em geral você pode. Então, toda ferramenta que chamascp_test.sh
precisaria ser consertada e chamadascp_test.py
em vez disso.Dê um nome ao roteiro
scp_test
. Você pode saber sescp_test
é executável examinando suas permissões. Se você quiser saber o que é, invoquefile scp_test
. Agora você pode reescrever o script em qualquer idioma que desejar, ou até mesmo compilar um binário, e você (ou qualquer pessoa/qualquer coisa) ainda pode executá-lo comoscp_test
.