Copiando um único arquivo para vários diretórios usando cp

12

Esta pergunta é uma espécie de sequela da minha pergunta anterior, Criando vários diretórios usandomkdir .

Eu estou usando o bashshell. Eu criei cinquenta diretórios, cada um começando com o prefixo "s", usando o comando:

mkdir $(printf "s%02i " $(seq 1 50))

que preenche o segundo dígito com zeros. Ou seja, os diretórios que eu obter são da forma s01, s02, ..., s49, s50.

Agora eu gostaria de usar cppara copiar um único arquivo (por exemplo test.txt) para cada um dos cinquenta diretórios. É possível fazer isso de maneira análoga à descrita acima? Por exemplo, o seguinte funcionaria? Eu sou relativamente novo no Unix / Linux, então não quero tentar isso até que alguém por favor me dê uma indicação de que é seguro.

cp test.txt $ (printf "s% 02i.txt" $ (seq 1 50))

Olhando para a manpágina cp, ela não parece ser cpcompatível com vários destinos como este, no entanto:

NAME
       cp - copy files and directories

SYNOPSIS
       cp [OPTION]... [-T] SOURCE DEST
       cp [OPTION]... SOURCE... DIRECTORY
       cp [OPTION]... -t DIRECTORY SOURCE...

DESCRIPTION
       Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.

       Mandatory  arguments  to  long  options are mandatory for short options
       too.
Andrew
fonte

Respostas:

7

Se você quiser usar a saída do seu comando para copiar o arquivo para cada diretório usando cp, sempre poderá canalizá-lo para xargs:

printf "s%02i " $(seq 1 50) | xargs -n 1 cp test.txt

Não deve haver nenhuma preocupação com a segurança de analisar a saída, pois você conhece seu formato e conteúdo com antecedência - o risco de encontrar metacaracteres e espaço nos nomes dos arquivos não é realmente um problema aqui.

Como alternativa, supondo que os diretórios já existam, você pode tentar algo como:

find . -maxdepth 1 -type d -name 's[0-9][0-9]' -print0 | xargs -0 -I {} cp test.txt {}

ou sem tubo:

find . -maxdepth 1 -type d -name 's[0-9][0-9]' -exec cp test.txt {} \;

Os dois últimos comandos encontrarão todos os arquivos no diretório atual e cp test.txtpara eles. A -maxdepth 1opção evitará que qualquer subdiretório receba o arquivo também. Esteja avisado que 's[0-9][0-9]'está combinando contra sseguido por quaisquer dois dígitos, o que significa se por algum motivo você tem s99no cwd, ele irá também receber uma cópia test.txt.

tojrobinson
fonte
8

Você também pode deixar o shell fazer as iterações com um forloop. Essa é a maneira mais básica que não depende de ferramentas externas como parallelou xargs, e acho mais fácil entender:

for name in $(printf "s%02i " $(seq 1 50)); do
    mkdir $name
    cp test.txt $name
done

Existem milhões de outras maneiras de escrever isso, por exemplo:

for name in $(seq -w 1 50); do
    mkdir s$name
    cp test.txt s$name
done

Se você deseja verificar o que seria executado antes de fazê-lo, pode fazer algo como anexar os comandos echo, o que imprimirá a linha em vez de executá-la:

for name in $(seq -w 1 50); do
    echo mkdir s$name
    echo cp test.txt s$name
done

saídas:

mkdir s01
cp test.txt s01
mkdir s02
cp test.txt s02
mkdir s03
cp test.txt s03
# etc.
Jim Paris
fonte
2

Você também pode usar o GNU paralelo . Supondo que você esteja no diretório que contém text.txt e seus 50 dirs estejam localizados /my/50dirs/path(como /my/50dirs/path/s01, /my/50dirs/path/s02etc), você executaria:

seq -w 01 50 | parallel -j1 cp text.txt /my/50dirs/path/s{}
don_crissti
fonte
2
É melhor fazer isso parallel -j1, caso contrário, haverá um trabalho por núcleo e, em uma máquina multicore, os trabalhos competirão por E / S.
Gilles 'SO- stop be evil'