Tenho problemas ao copiar muitos arquivos em diretórios diferentes. Deixe-me explicar melhor:
Digamos que eu tenha o seguinte em um diretório:
$ ls
file1 file2 file3 file4 file5 dir1 dir2 dir3
e quero copiar todos os arquivos* em todos os diretórios* com um único comando. Eu tentei com:
echo dir{1..3} | xargs cp file{1..5} '{}' \;
Minha intenção era dizer ao xargs para processar cada dir* do echo e copiar todos os arquivos na entrada processada, mas isso e similares não funcionaram. Gostaria de evitar o uso de um script porque é uma tarefa que devo repetir em cerca de 20 diretórios e os nomes dos arquivos são um pouco diferentes, então prefiro modificar um comando em vez de um script.
Responder1
echo dir[1-3] | xargs -r -n1 cp file[1-5]
Responder2
Você está cometendo um pequeno erro ao usar xargs. Sem o parâmetro -n, o xargs anexa todos os parâmetros da entrada ao comando e echo dir{1..3}
não adicionará o retorno de carro necessário entre cada entrada, portanto o xargs considerará o resultado como um parâmetro.
xargs tem uma opção -n que pode limitar o número de entradas, e você precisa listar os diretórios com \n ou \0 como separador:
find . -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 -n 1 cp file{1..5}
O comando find irá procurar todos os diretórios do atual e usar o \0 como separador (que funciona melhor se você tiver diretórios com espaços) e xargs usa o \0 como separador e iniciar o comando cada vez com apenas 1 parâmetro.
Responder3
Algo como o seguinte deve funcionar se eles realmente tiverem esses nomes:
#!/bin/bash
shopt -s nullglob
for dir in dir*/; do
cp file* "$dir"
done
Se você deseja copiar todos os arquivos para todos os diretórios, independentemente do nome:
#!/bin/bash
shopt -s nullglob dotglob
for dir in */; do
for file in *; do
[[ -f $file ]] && cp "$file" "$dir"
done
done
Responder4
Você está quase lá. Você precisa executar um cp
comando separado para cada diretório de destino, pois cp
faz apenas uma cópia de cada arquivo de origem. O objetivo principal xargs
é executar um comando sobre vários argumentos, mas você pode instruí-lo a passar um único item por vez com a -n
opção. Também {} ;
é a sintaxe de find … -exec
; você não precisa (e não pode usá-lo) com xargs
.
echo dir{1..3} | xargs -n 1 cp file{1..5}
Observe que isso só funciona se os nomes dos seus diretórios não contiverem nenhum espaço em branco ou qualquer um dos caracteres \'"
, porque xargs
não há como saber se esses caracteres fazem parte dos nomes dos arquivos e não estão entre aspas e separando os arquivos de entrada. Um método alternativo que não apresenta esse problema é usar um shell loop:
for d in dirs{1..3}; do
cp file{1..5} "$d"
done
Tudo isso pressupõe que você possa distinguir facilmente entre arquivos e diretórios por seus nomes. Se não puder, você pode combinar os diretórios adicionando um /
no final; por exemplo, */
corresponde a todos os diretórios nos diretórios atuais, foo[0-9]*/
corresponde a todos os diretórios cujo nome começa com foo
um dígito, etc. Não existe uma maneira semelhante de corresponder apenas não-diretórios na maioria dos shells, mas se você passar diretórios para cp
sem nenhum argumento para informá-lo para fazer uma cópia recursiva, os diretórios são ignorados com uma mensagem de erro.
for d in */; do
cp * "$d"
done
No zsh, você pode usareliminatórias globaispara corresponder apenas a determinados tipos de arquivo.
for d in *(/); do
cp *(.) $d
done