find -exec no script bash com expansão variável

14

Estou tentando executar um comando semelhante ao abaixo em um script bash. Ele deve pesquisar em todas as subpastas de $sourcedir e copiar todos os arquivos de um determinado tipo para o nível raiz de $targetdir .

#!/bin/bash

# These are set as arguments to the script, not hard-coded
sourcedir="/path/to/sourcedir"
targetdir="/path/to/targetdir"

find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2/'basename "$1"'"' "{}" "$targetdir" \;

Isso parece estar bem próximo, exceto que {} não está sendo passado como $2 to -exec sh -c ...

Eu gostaria de fazer isso o mais próximo possível do "caminho certo", com tolerância para caracteres especiais em nomes de arquivos (especificamente caracteres de aspas simples).

Editar: vejo pessoas sugerindo o uso de xargs ou encadeamento de argumentos. Fiquei com a impressão de que isso é bom apenas para um número limitado de argumentos. Se eu tiver, por exemplo, milhares de arquivos .jpg que estou tentando copiar de vários diretórios de galerias para um diretório gigante de slideshow, os argumentos de encadeamento de soluções ainda funcionarão?

Editar 2: Meu problema foi que eu estava faltando um _ antes da minha primeira opção para sh no comando -exec . Para quem está curioso sobre como fazer o comando find funcionar, adicione o _ e tudo ficará bem:

find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2"' _ "{}" "$targetdir" \;

Eu aceitei uma resposta abaixo, porque ela realiza a mesma tarefa, mas é mais eficiente e elegante.

    
por Matthew 02.02.2012 / 20:17

4 respostas

6

Você deseja copiar arquivos de um tipo específico para um diretório específico? Isso é feito melhor com xargs e você não precisa nem mesmo de sh . Essa é uma maneira mais apropriada de fazer isso, também deve ser executada com mais eficiência.

find "$sourcedir" -type f -name "*.type" | xargs cp -t targetdir

Se você precisar manipular nomes de arquivos especiais, use NULL como seu separador

find "$sourcedir" -type f -name "*.type" -print0 | xargs -0 cp -t "$targetdir"
    
por 02.02.2012 / 20:57
5

Você precisa passar {} como um argumento para o shell e fazer um loop sobre cada arg.

find "$sourcedir" -type f -name "*.type" -exec sh -c 'for f; do cp "$f" "$0"; done' "$targetdir" {} +

Nota : A maneira como isso funciona é que o primeiro argumento para um shell é o nome do shell , podemos explorar isso passando o nome como $targetdir e, em seguida, use o parâmetro especial $0 dentro do script de shell para acessar esse targetdir.

    
por 02.02.2012 / 20:24
4

Se você não acredita na igreja de xargs:

find "$sourcedir" -type f -name "*.mp3" -exec cp -t "$targetdir" {} +

Explicação:

cp -t a b c d 

copia b, c e d para o dir de destino a.

-exec cmd {} +

invoca o comando em um grande grupo de arquivos de uma só vez, não um após o outro (o que é padrão, se você usar ";" em vez de + ). É por isso que tem que puxar o alvo para a frente e marcá-lo explicitamente como alvo.

Isso funciona para o gnu-find e não para outras implementações do find. Claro que também depende do -t -flag.

O TechZilla, é claro, está tão certo, já que sh não é necessário para invocar o cp.

Se você não usa xargs , o que na maioria das vezes é desnecessário em combinação com find , você não precisa aprender o -print0 e -0 sinalizador.

    
por 03.02.2012 / 01:01
0
read -p "SOURCE: " sourcedir
read -p "TYPE: " type
read -p "TARGET: " targetdir
find -L $sourcedir -iname "*.$type" -exec cp -v {} $targetdir \;
    
por 05.11.2014 / 03:21