Como faço para escapar de personagens estranhos em um script bash?

5

Eu não sou profissional em scripts ou encontrar comandos que assim nunca (apenas um aviso). Estou tentando criar um script que possa mover todos os meus podcasts de mp3 para uma pasta que eu possa mover para o meu telefone.

Então o script que eu fiz precisa mover todos os mp3's (mesmo aqueles com caminhos estranhos). Eu criei um script como segue e parece * fazer o que eu pretendia, mas continua dando erros da seguinte forma:

find /home/jason/gPodder/ -name '*.mp3' -exec bash " cp '{}' /home/jason/gPodder/mp3/ " \;
Which returns:    
bash:  cp '/home/jason/gPodder/Downloads/The Documentary/TheDocumentary20170823-GoingGreenInTheOilState.mp3' /home/jason/gPodder/mp3/ : No such file or directory 

Mas se eu copiar o bash 'command' acima, não há problema. Por favor, você poderia me ajudar a entender qual é o meu erro no script.

Obrigado

    
por Jason Smit 29.08.2017 / 14:46

3 respostas

7

Como @Kusalananda disse , você está perdendo um -c para poder usar um script in-line.

Mas, mesmo assim, nunca incorpore o {} no código shell, que seria uma vulnerabilidade de injeção de comando arbitrária (pense na instância de um arquivo chamado '$(reboot)'.mp3 com seu exemplo). Em vez disso, torne-o um argumento do script in-line (supondo que você precise de um script in-line aqui e que o cp seja apenas um exemplo).

find ... -exec sh -c 'cp "$1" /home/jason/gPodder/mp3' sh {} \;

(você também não precisa de bash apenas para isso. Seu sh funcionará tão bem).

Ou melhor ainda, passe vários argumentos de uma só vez para cp :

find ... -exec sh -c 'cp "$@" /home/jason/gPodder/mp3' sh {} +

Com o GNU cp , você também pode:

find ... -exec cp -t /home/jason/gPodder/mp3 {} +
    
por 29.08.2017 / 14:52
6

Não torne isso mais complicado do que precisa ser.

find /home/jason/gPodder/ -name '*.mp3' -exec cp {} /home/jason/gPodder/mp3/ \;

ou possivelmente

find /home/jason/gPodder/ -type f -name '*.mp3' -exec cp {} /home/jason/gPodder/mp3/ \;

para considerar apenas arquivos regulares.

Para copiar somente o arquivo se nenhum arquivo com o mesmo nome já existir na pasta de destino, algumas cp implementações suportam uma opção -n para isso ou você pode usar -i com stdin redirecionado de /dev/null (mas cuidado, esses não funcionam se o alvo é do tipo diretório) ou faça algo como:

find /home/jason/gPodder/ -type f -name '*.mp3' \
    ! -execdir test -e /home/jason/gPodder/mp3/{} \; \
    -exec cp {} /home/jason/gPodder/mp3/ \;

-execdir é uma extensão para o padrão POSIX find , mas é suportado por muitas implementações find modernas. Ele executa como -exec , mas executa o comando com o diretório pai da coisa encontrada como seu diretório de trabalho. Além disso, {} será o nome de base da coisa encontrada ( file.mp3 ou ./file.mp3 dependendo da implementação find ) e não o caminho completo dela. Veja man find .

O erro deriva de bash "somecommand" . Ao invocar bash dessa maneira, bash espera que somecommand seja o caminho para um arquivo de script, não uma série de comandos de shell, e não é possível encontrar um script com o nome que você está dando. / p>

Para executar uma série arbitrária de comandos shell, você precisa de bash -c "somecommand" .

Mas, neste caso, use apenas -exec cp como acima ou como na resposta de Stéphane Chazelas .

    
por 29.08.2017 / 14:50
0

Outros apontaram as citações & problemas de execução.

Vou sugerir que você não use find -exec, mas, em vez disso, encontre uma lista de arquivos e canalize essa lista para xargs e cp. Usando a opção print0 irá ajudá-lo a contornar quaisquer caracteres "engraçados" em nomes de arquivos e diretórios

por exemplo,

find sourcepath -name \*.mp3 -print0 \
    | xargs -0 cp -t destinationpath

O benefício disso é que o xargs irá coletar vários nomes de arquivos juntos para encontrá-los e entregá-los ao cp ao mesmo tempo, assim cada instância cp pode copiar 20 ou 100 arquivos ao invés de iniciar 1 cp invocação para cada arquivo. O xargs irá cuidar de colocar nomes de arquivos suficientes na linha de comando do cp para você.

Você também pode adicionar a opção -P n ao xargs e iniciar vários processos cp em paralelo.

Com base em que seus arquivos estão no mesmo sistema de arquivos que a pasta mp3 de destino. Você pode adicionar -l ao cp e vai vincular os arquivos ao destino, em vez de copiá-los.

por exemplo,

find sourcepath -name \*.mp3 -print0 \
    | xargs -0 -P 5 \
    cp -l -t destinationpath
    
por 29.08.2017 / 22:53