Exclui caracteres para o padrão de arquivo SCP

2

Existe uma maneira de criar uma expressão para scp com a qual eu possa copiar o arquivo

file-name-version-1.2.1.jar

sem copiar os arquivos

file-name-version-1.2.1-sources.jar
file-name-version-1.2.1-javadoc.jar

sem saber os números exatos da versão? file-name-version-*.*.*.jar não funciona por razões óbvias. Estou procurando uma sintaxe como

file-name-version-\d.\d.\d.jar

ou algo similar.

    
por Vince 29.11.2013 / 12:36

4 respostas

5

Uma coisa a ter em mente é que o nome do arquivo é passado não modificado para o shell de login do usuário remoto.

Se você fizer isso:

 scp user@remote-machine:'something' ...

Na máquina remota, sshd executará o shell de login de user como:

 that-shell -c 'scp -f something'

E é esse shell que expandirá os padrões lá.

O que isso significa é que a maneira como o padrão é expandido dependerá do shell de login que o usuário remoto está usando. Quando esse shell for bash , isso também dependerá do que o usuário tem em ~/.bashrc , ou o que existe em /etc/bash.bashrc (por exemplo, bash-completion chamado a partir de lá quando instalado, ativa globbing estendido no estilo ksh) já que, por algum motivo, bash lê esses quando é chamado de ssh (mesmo que não seja um shell interativo).

O que isso também significa é que se something for, por exemplo, 'blah; rm -rf "$HOME"' , isso terá conseqüências catastróficas.

Esse é um dos misdesigns de ssh .

Se você quiser forçar um shell específico a expandir esse something em uma lista de arquivos, use este truque:

LC_SCPFILES=something scp -o SendEnv=LC_SCPFILES "localhost:</dev/null
  bash -O extglob -c 'exec scp -f -- \$LC_SCPFILES';exit" /dest/dir

Isso só funciona se o shell de login do usuário remoto for um shell Unix normal (pelo menos das famílias Bourne, csh, rc ou fish) e bash estiver instalado lá e sshd permitir a passagem de variáveis de ambiente cujo nome começa com LC_ .

O truque é que a maioria das sshd deployments permite passar variáveis de ambiente cujo nome começa com LC_ (necessário para que um usuário espanhol possa receber mensagens de erro dos comandos remotos em espanhol (em vez do idioma padrão no sistema remoto) ou a linguagem do usuário remoto), por exemplo).

Então, aqui, passamos something em uma variável de ambiente LC_SCPFILES .

Na máquina remota, sshd será executado:

that-shell -c 'scp -f </dev/null
  bash -O extglob -c '\''exec scp -f -- $LC_SCPFILES'\'';exit'

Como seu stdin é redirecionado de /dev/null , o primeiro scp sairá imediatamente. Em seguida, iniciamos nosso shell de escolha ( bash ), com a opção extglob e com a linha de comando exec scp -f -- $LC_SCPFILES para interpretar.

Como bash será executado em um processo filho de that-shell (que aplicamos adicionando um ;exit posteriormente), bash não fornecerá o ~/.bashrc , portanto, podemos esperar o comportamento padrão de bash there (a menos que, de alguma forma, that-shell , na inicialização, defina as variáveis de ambiente BASHOPTS , SHELLOPTS ou BASH_ENV ).

Como $LC_SCPFILES não é citado, ele estará sujeito a divisão de palavras e geração de nome de arquivo (globbing), mas não a outras expansões de shells, e não fará coisas como rm -rf "$HOME" apenas porque something o contém.

Agora que nos certificamos de que o padrão é expandido em bash -O extglob na máquina remota, podemos usá-lo para corresponder a um padrão que usa operadores glob estendidos (usando aqui uma função auxiliar):

safer_scp() (
  file=$1; shift
  export LC_SCPFILES="${file#*:}"
  exec scp -o SendEnv=LC_SCPFILES "${file%%:*}:</dev/null
    bash -O extglob -c 'exec scp -f -- \$LC_SCPFILES';exit" "$@"
)
safer_scp user@host:'file-name-version-+([0-9]).+([0-9]).+([0-9]).jar' .

O +([0-9]) , com extglob em bash , corresponde a um ou mais dígitos decimais. Portanto, o padrão acima corresponderia a file-name-version-1.2.3.jar e file-name-version-12.123.1234.jar , por exemplo.

(observe que safer_scp acima supõe que o primeiro argumento é host:file-patterns , coisas como safer_scp -r ... ou safer_scp host1:f1 host2:f2 ... não funcionam. Se você quiser usar -r , o mais fácil é definir um safer_scp_r function onde scp -f acima é substituído por scp -r -f ).

Você pode desativar a divisão de palavras adicionando um IFS=; antes do exec scp... acima.

Observe também que estamos usando bash aqui, pois ele está instalado em todos os sistemas GNU, mas se você sabe que zsh está instalado no sistema remoto, você pode usar

zsh -o extendedglob -o globsust

em vez de se beneficiar do poder total de zsh globbing (recursivo, qualificadores ...)

(adicione -o shwordsplit se quiser também a divisão de palavras).

Por exemplo:

safer_scp() (
  file=$1; shift
  export LC_SCPFILES="${file#*:}"
  exec scp -o SendEnv=LC_SCPFILES "${file%%:*}:</dev/null
    zsh -o extendedglob -o globsubst -c 'exec scp -f -- \$LC_SCPFILES';exit" "$@"
)
safer_scp user@host:'file-name-version-<->(.<->)#.jar' .

Copia file-name-version-1.jar e file-name-version-1.2.3.4.5.jar ( <x-y> é qualquer número inteiro decimal de x a y , <-> é qualquer número inteiro decimal, # é como o operador * regexp (0 ou mais do átomo anterior))

    
por 29.11.2013 / 14:31
1

Eu acho que você quer

file-name-version-[0-9].[0-9].[0-9].jar
    
por 29.11.2013 / 12:38
1

Neste caso particular

scp 'user@host:file-name-version-*[0-9].jar' .

pode ser o suficiente para você.

    
por 29.11.2013 / 17:09
1

Para maior flexibilidade, use rsync em vez de scp.

rsync --include='file-name-*.jar' \
      --exclude='*-sources.jar' --exclude='*-javadoc.jar' \
      example.com:/some/directory/ local/directory/
    
por 30.11.2013 / 01:40

Tags