Estou tentando executar um comando semelhante ao abaixo em um script bash. Ele deve procurar por todas as subpastas $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 bem próximo, exceto que {}
não está sendo repassado $2
para-exec sh -c ...
Eu gostaria de fazer isso o mais próximo possível da "maneira correta", com tolerância a caracteres especiais em nomes de arquivos (especificamente aspas simples).
Editar: vejo pessoas sugerindo o uso xargs
ou encadeamento de argumentos. Fiquei com a impressão de que isso não é aceitável 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 da galeria para um diretório gigante de apresentações de slides, as soluções que encadearão argumentos ainda funcionarão?
Edit 2: Meu problema era que faltava um _
antes da minha primeira opção para sh no -exec
comando. Para quem estiver curioso sobre como fazer o comando find funcionar, adicione _
oe tudo ficará bem:
find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2"' _ "{}" "$targetdir" \;
Aceitei uma resposta abaixo, porém, porque ela realiza a mesma tarefa, mas é mais eficiente e elegante.
fonte
xargs
foi criado, para lidar automaticamente com grandes quantidades de argumentos em comandos regulares que tinham limites. Além disso, a maioria dos limites máximos de argumentos foi amplamente aprimorada para os utilitários GNU padrão. Você também verá um benefício no desempenho, evitando todos os garfos do processo, que em milhares de arquivos são relevantes.Respostas:
Deseja copiar arquivos de um tipo específico, para um diretório específico? É melhor fazer isso
xargs
, e você nem precisa dissosh
. Essa é uma maneira mais apropriada de fazê-lo, também deve ser executada com mais eficiência.Se você precisar manipular nomes de arquivos especiais, use
NULL
como seu separadorfonte
-print0
afind
e-0
axargs
NULL
não é necessário se você usar'{}'
, é importante quando não o fizer. O benefício real entre um dos outros, além daPOSIX
conformidade, é o desempenho.Você precisa passar
{}
como argumento para o shell e fazer um loop sobre cada argumento.Nota : A maneira como isso funciona é que o primeiro argumento para um shell é o nome do shell . Podemos explorar isso passando o nome como o
$targetdir
e, em seguida, usar o parâmetro especial$0
dentro do script do shell para acessar o targetdir.fonte
"$targetdir"
não é expandido entre aspas simples.Se você não acredita na igreja de xargs:
Explicação:
copia b, c para o dir de destino a.
chama o comando em um grande grupo de arquivos de uma só vez, não um após o outro (que é padrão, se você usar em
";"
vez de+
). É por isso que é necessário puxar o targetdir para frente e marcá-lo explicitamente como alvo.Isso funciona para o gnu-find e pode não ser para outras implementações do find. Claro que também depende da bandeira -t-bandeira.
É claro que o TechZilla está certo até agora, pois
sh
não é necessário para invocar o cp.Se você não usar
xargs
, o que geralmente é desnecessário em combinação comfind
, será salvo do aprendizado da sinalização-print0
e-0
.fonte
xargs
. Maior exemplo, e se você não estiver encontrando arquivos? Eu uso xargs no lugar defor
loops gerais o tempo todo,find
é muito menor em escopo. Além disso,find
apenas suporta que,+
se você estiver usando o GNUfind
, ele não está definido no POSIX. Portanto, embora você sinta-se livre para preferirfind
sozinho, ele não faz tudo que o xargs faz. Quando você considera o GNU,xargs
também obtém o-P
que é multi-core. Vale a pena aprenderxargs
independentemente.fonte