copiando vários arquivos para vários diretórios

4

Eu tenho um problema 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 eu quero copiar todos os arquivos * em todos os dir * 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 funcionavam. Eu gostaria de evitar o uso de um script porque é uma tarefa que tenho que repetir por cerca de 20 diretórios e os nomes dos arquivos são um pouco diferentes, então eu prefiro modificar um comando ao invés de um script.

    
por Luigi Tiburzi 07.06.2012 / 23:21

4 respostas

3

echo dir[1-3] | xargs -r -n1 cp file[1-5]

    
por 08.06.2012 / 04:02
3

Você está cometendo um pequeno erro no uso de xargs. Sem o parâmetro -n, xargs anexa todos os parâmetros na entrada para o comando e echo dir{1..3} não adicionará o retorno de carro necessário entre cada entrada, portanto os xargs considerarão o resultado como um parâmetro.

xargs tem uma opção -n que pode limitar o número de entrada, e você precisa listar os diretórios com um \ n ou \ 0 como separador:

find . -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 -n 1 cp file{1..5}

O comando find procurará todos os diretórios no atual e usará o \ 0 como separador (que funciona melhor se você tiver diretórios com espaços) e o xargs usar o \ 0 como separador e iniciar o comando a cada vez com apenas 1 parâmetro.

    
por 08.06.2012 / 00:54
2

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
    
por 07.06.2012 / 23:55
1

Você está quase lá. Você precisa executar um comando cp separado para cada diretório de destino, porque cp faz apenas uma cópia de cada arquivo de origem. O objetivo principal de xargs é executar um comando em vários argumentos, mas é possível informar que ele passe um único item por vez com a opção -n . 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 diretórios não contiverem nenhum espaço em branco ou nenhum dos caracteres \'" , porque xargs não tem como informar se esses caracteres fazem parte dos nomes de arquivos e não estão citando e separando arquivos de entrada . Um método alternativo que não tem esse problema é usar um loop de shell:

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 você não puder, poderá corresponder 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 e um dígito, etc. Não existe uma maneira semelhante de corresponder apenas a não diretórios na maioria dos shells, mas se você passar os diretórios para cp sem nenhum argumento para dizer para fazer uma cópia recursiva, os diretórios são ignorados com uma mensagem de erro.

for d in */; do
  cp * "$d"
done

Em zsh, você pode usar os qualificadores para corresponder apenas a determinados tipos de arquivo.

for d in *(/); do
  cp *(.) $d
done
    
por 08.06.2012 / 01:43

Tags