sh cópia recursiva (cp -r) - Como excluir subpasta

7

Eu preciso executar um script remoto usando ssh via Ruby ( net / ssh ) para copie recursivamente uma pasta e exclua uma subpasta. Eu estou procurando a maneira mais rápida de fazer isso, então rsync não é bom. Além disso, entendo que ssh usa sh e não bash .

No bash eu faço:

cp -r srcdir/!(subdir) dstdir

e funciona bem. No entanto, quando eu inicio o script via ssh eu recebo o erro

sh: 1: Syntax error: "(" unexpected

porque está usando sh .

Eu verifiquei a página sh man, mas não há opção para excluir arquivos.

É minha suposição de ssh usando sh correto? Alguma sugestão alternativa?

EDIT 1: Caso seja útil, a saída de sudo cat /etc/shells é a seguinte:

# /etc/shells: valid login shells
/bin/sh
/bin/dash
/bin/bash
/bin/rbash
/usr/bin/tmux
/usr/bin/screen

EDIT 2: ESTÁ BEM. Então bash está disponível e isso não parece ser o problema. Eu verifiquei que o ssh está realmente usando bash . O problema parece estar relacionado ao escape de parênteses ou ponto de exclamação. Eu tentei executar o comando a partir do shell (macos) e este é o comando real:

ssh -i .ssh/key.pem [email protected] 'mkdir /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; cp -r /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!\(constant\) /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; ln -s /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/constant /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N/constant'

Desta forma, recebo um erro diferente

cp: cannot stat '/home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!(constant)': No such file or directory

EDIT 3: Com base nos comentários, alterei meu comando adicionando extglob

Se eu usar

ssh -i .ssh/key.pem [email protected] 'shopt -s extglob; mkdir /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; cp -r /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!\(constant\) /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; ln -s /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/constant /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N/constant'

Eu recebo o seguinte erro:

cp: cannot stat '/home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!(constant)': No such file or directory

Se eu não fugir dos parênteses, obtenho

bash: -c: line 0: syntax error near unexpected token '('
    
por Rojj 19.08.2018 / 13:23

6 respostas

10

O SSH executa seu shell de login no sistema remoto, o que quer que seja. Mas !(foo) requer shopt -s extglob , o que talvez você não tenha definido no controle remoto.

Tente ver se o SSH executa o Bash no lado remoto:

ssh me@somehost 'echo "$BASH_VERSION"'

Se isso imprimir alguma coisa, mas seus scripts de inicialização não definirem extglob , você poderá fazer isso manualmente no comando passado para ssh :

ssh me@somehost 'shopt -s extglob
    echo srcdir/!(subdir)'                                 
 # or
ssh me@somehost $'shopt -s extglob\n echo srcdir/!(subdir)'   

extglob afeta a análise da linha de comando e só entra em vigor após uma nova linha, então temos que colocar uma nova linha literal lá, um ponto-e-vírgula não é suficiente.

ssh me@somehost 'shopt -s extglob; echo srcdir/!(subdir)'

Além disso, se você escapar dos parênteses com barras invertidas, eles perderão suas propriedades especiais, como qualquer outro caractere glob. Isto não é o que você deseja fazer neste caso.

$ touch foo bar; shopt -s extglob; set +o histexpand
$ echo *
bar foo
$ echo !(foo)
bar
$ echo \*
*
$ echo !\(foo\)
!(foo)
    
por 19.08.2018 / 14:24
10

Não sei por que você acha que o rsync seria lento. A velocidade de uma cópia é determinada principalmente pela velocidade do disco. O Rsync tem muitas opções para especificar o que você quer incluir e excluir, para que você tenha um controle muito melhor do que o shell globbing.

Conforme o manual do bash declara, o !(patter) é reconhecido apenas no bash se extglob estiver definido. No seu exemplo, você não definiu extglob . Além disso, um bash iniciado como sh ainda é bash , mas desativará algumas extensões para compatibilidade.

O servidor SSH iniciará o shell de login do usuário, conforme especificado em /etc/passwd . Você pode alterar o shell ou usar esse shell para iniciar outro shell que melhor se adapte às suas necessidades.

    
por 19.08.2018 / 14:18
6

Algumas notas primeiro:

  • o servidor ssh não inicia sh para interpretar a linha de comando enviada pelo cliente, ele executa o shell de login do usuário no host remoto, como that-shell -c <the-string-provided-by-the-client> . O shell de login do usuário remoto pode ser qualquer coisa. Lembre-se de que alguns shells como tcsh , fish ou rc têm uma sintaxe muito diferente da de sh .
  • é realmente uma linha de comando, ou mais exatamente uma string (que pode conter caracteres de nova linha, então várias linhas). Mesmo se você fizer ssh host cmd arg1 'arg 2' , em que cmd , arg1 e arg 2 são três argumentos passados para ssh , ssh concatena esses argumentos com espaços e realmente envia a string cmd arg1 arg 2 para sshd e o shell remoto dividiria isso em cmd , arg1 , arg e 2 .
  • !(subdir) é um operador glob (um operador ksh glob também é suportado por zsh -o kshglob e bash -O extglob ). Como todos os globs, ele exclui arquivos ocultos, portanto, cuidado, pode haver outros arquivos que ele exclui.

Aqui, para evitar o problema de descobrir a sintaxe certa para o shell remoto, você pode dizer que outro shell para iniciar o shell desejado e alimentá-lo via stdin (uma das opções listadas em Como executar um comando simples arbitrário sobre o ssh sem conhecer o shell de login do usuário remoto? )

ssh host 'bash -O extglob -O dotglob' << 'EOF'
cp -r srcdir/!(subdir) dstdir/
EOF

bash -O extglob -O dotglob é uma linha de comando que é entendida da mesma forma por todos os principais shells, incluindo os de tipo Bourne, csh, rc, fish ... O acima funcionaria enquanto bash estivesse instalado e estivesse no $PATH do usuário (padrão $PATH , possivelmente modificado pelo shell de login do usuário, como com ~/.zshenv para zsh , ~/.cshrc para csh , ~/.bashrc para bash ).

POSIXly (embora, na prática, você possa descobrir que mais sistemas têm um comando bash do que um comando pax ), você poderia fazer:

ssh host sh << 'EOF'
cd srcdir && pax -rw -'s|^\.//\./subdir\(/.*\)\{0,1\}$||' .//. /path/to/destdir/
EOF

-s aplica substituições aos caminhos que estão sendo transferidos. Quando essa substituição se expande para nada, o arquivo é excluído. O problema é que as substituições também se aplicam ao destino de links simbólicos. É por isso que usamos .//. acima para diminuir a probabilidade de um link simbólico ser afetado.

    
por 19.08.2018 / 19:43
4

Não acho que ssh esteja limitado a usar sh . Depende do que está instalado no sistema de destino, como o usuário está configurado e quais shells são permitidos em /etc/shells .

Você considerou o comando chsh ?

    
por 19.08.2018 / 13:28
4

Se você quiser fazer isso de maneira rápida, pode olhar para rsync com um algoritmo de criptografia diferente. Isso lhe dá a opção de excluir facilmente, etc., a um sacrifício de pouca velocidade.

rsync -aHAXxv --numeric-ids --progress -e "ssh -T -c arcfour -o Compression=no -x" user@<source>:<source_dir> <dest_dir>

junto com a adição da criptografia arcfour à linha que começa com Ciphers em /etc/ssh/ssh_config , se ainda não estiver ativado, oferece uma velocidade aceitável.

AVISO: a criptografia arcfour é insegura . NÃO execute isso em canais inseguros. Se você estiver preocupado com o acesso ao servidor de canais inseguros usando arcfour encryption, altere a etc/ssh/ssh_config com uma parte específica do host para seu host de origem - Crie uma seção Host em seu ssh_config para seu host de origem, você pode usar Ciphers arcfour para espelhar a opção -c acima, o que restringe a criptografia arcfour apenas a esse host.

Para detalhes, consulte as páginas ssh_config man.

No entanto, se suas CPUs suportarem o conjunto de instruções AES-NI, tente mudar para [email protected] (sim, esse é o nome da cifra, incluindo o @ stuff), que usará o incrivelmente rápido (com AES- NI) AES128-GCM.

Portanto, com uma CPU compatível com AES-NI, altere "ssh -T -c arcfour -o Compression=no -x" para "ssh -T -c [email protected] -o Compression=no -x" para obter resultados mais seguros.

Explicação

rsync

  • (não use -z , é muito mais lento)
  • a : modo de arquivo - rescursivo, preserva o proprietário, preserva as permissões, preserva os tempos de modificação, preserva o grupo, copia os links simbólicos como links simbólicos, preserva os arquivos de dispositivos.
  • H : preserva hard-links
  • A : preserva as ACLs
  • X : preserva os atributos estendidos
  • x : não cruze os limites do sistema de arquivos
  • v : aumenta a verbosidade
  • --numeric-ds : não mapeia valores de uid / gid por usuário / nome de grupo
  • se precisar sincronizar, adicione --delete : excluir arquivos estranhos de dir dirs (limpeza diferencial durante a sincronização)
  • --progress : mostra o progresso durante a transferência

ssh

  • T : desative o pseudo-tty para diminuir a carga da cpu no destino.
  • c arcfour : use a criptografia SSH mais fraca, mas mais rápida. Deve especificar "Cifras arcfour" em sshd_config no destino.
  • o Compression=no : desative a compactação SSH.
  • x : desative o encaminhamento do X se estiver ativado por padrão.

O bife está nas opções ssh - se você usar apenas rsync -av e -e ssh -T -c arcfour -o Compression=no -x" , também poderá obter essas velocidades.

Comparação:

  • 13,6 MB / s rsync -az
  • 16,7 MB / s scp -Cr
  • 44,8 MB / s rsync -a
  • 59,8 MB / s sftp
  • 61,2 MB / s scp -r
  • 61,4 MB / s sftp -R 128 -B 65536
  • 62,4 MB / s rsync -a -P -e "ssh -T -c arcfour -o Compression=no -x"
  • 143,5 MB / s scp -r -c arcfour
  • 144,2 MB / s sftp -oCiphers=arcfour

Fontes :

link

link

    
por 19.08.2018 / 14:31
2

De acordo com meus cálculos, a cópia completa mais rápida está sempre usando 'tar' (aqui assumindo o GNU tar ou compatível).

mkdir -p photos2 &&
  tar -C photos -cf - --exclude=./.thumbcache . |
  tar -C photos2 -xpf -

E tar tem várias opções para manipular atributos, permissões e seleção / exclusão de arquivos. Por exemplo, o comando acima exclui a subpasta de nível superior chamada .thumbcache durante a cópia.

    
por 20.08.2018 / 04:43

Tags