Como copiar um arquivo para vários diretórios usando o comando gnu cp

210

É possível copiar um único arquivo para vários diretórios usando o comando cp?

Eu tentei o seguinte, que não funcionou:

cp file1 /foo/ /bar/
cp file1 {/foo/,/bar}

Eu sei que é possível usar um loop for ou find. Mas é possível usar o comando gnu cp?

Tom Feiner
fonte

Respostas:

106

Não, cppode copiar várias fontes, mas apenas copiará para um único destino. Você precisa organizar cpvárias vezes - uma vez por destino - para o que deseja fazer; usando, como você diz, um loop ou alguma outra ferramenta.

sombra da Lua
fonte
Obrigado pela resposta! Agora que penso um pouco mais, sem sinalizadores extras (que não existem), o cp não saberá qual é a fonte e qual é o diretório DEST.
Tom Feiner
10
Esta não é a resposta correta. Por favor, veja a resposta de Robert Gamble.
PlagueHammer
23
@ Noturno: qual parte do que eu disse está incorreta? Robert dá um exemplo do uso de outra ferramenta para invocar o cp várias vezes, como eu sugiro. Existem muitas soluções possíveis que envolvem o uso de outras ferramentas ou construções para fazer isso, mas o OP indicou que ele já estava ciente de que isso é possível.
moonshadow
2
Infelizmente, seria ótimo para cp (e scp) suportar esse recurso. No entanto, podemos usar tee para fazer a divisão. superuser.com/questions/32630/…
Simon
4
@moonshadow: Claro que sua resposta está correta. Acho que o PlagueHammer quer dizer que, nesse contexto, a outra resposta é mais útil. Talvez você também inclua algo assim em sua resposta?
Peaceful
585

Você não pode fazer isso cpsozinho, mas pode combinar cpcom xargs:

echo dir1 dir2 dir3 | xargs -n 1 cp file1

Irá copiar file1para dir1, dir2e dir3. xargschamará cptrês vezes para fazer isso, consulte a página de manual para xargsobter detalhes.

Robert Gamble
fonte
3
Mais informações sobre xargs: cyberciti.biz/faq/…
Chris Bier
24
@ Simon como assim? "Você não pode fazer isso cpsozinho" Só porque a resposta tentou ser útil sugerindo outra maneira não significa que a pergunta não foi respondida.
Nicole
3
@NickC O solicitante especificou: "Eu sei que é possível usar um loop for ou find. Mas é possível usar o comando gnu cp?" A boa resposta é a que é aceita.
Simon
25
Estipular que as respostas sejam aceitas com base no fato de responderem tecnicamente à pergunta seria insuportavelmente pedante e não seria realmente útil.
Gamão
4
Muito útil! Para outros iniciantes como eu: você não pode usar o regex com o cp, mas na primeira parte deste comando (por exemplo echo dir[1-3] | xargs -n 1 cp filename).
Jason
77

Os curingas também funcionam com o código Roberts

echo ./fs*/* | xargs -n 1 cp test 
Paulo
fonte
e todo o comentário ... Por exemplo, para mover um arquivo de propriedade raiz (um link simbólico na verdade) que estava na minha área de trabalho para todos os usuários, eu primeiro tive que sudo su (não funcionou de outra maneira) e depois usei: echo / home / * / Desktop / | xargs -n 1 cp -av / home / nome_do_usuário / Desktop / arquivo.
David G
19

Tanto quanto eu posso ver, você pode usar o seguinte:

ls | xargs -n 1 cp -i file.dat

A -iopção de cpcomando significa que você será perguntado se deseja substituir um arquivo no diretório atual com o file.dat. Embora não seja uma solução completamente automática, funcionou para mim.

Evgeny
fonte
1
Embora seja bom ter adicionado a -iproteção, isso não o levará a escrever todos os arquivos? em vez de copiar para os diretórios?
Hedgehog
1
@ Ouriço Bem, acho que este comando é útil quando há um arquivo no diretório e se deseja copiá-lo para subdiretórios do diretório. Nesse caso, um arquivo pode ser substituído apenas uma vez. Obrigado pela sua pergunta!
Evgeny
2
Para mim, imprimiu uma série de cp: overwriteperguntas, mas não precisei responder nenhuma delas e não substitui os arquivos.
Evgeni Sergeev
Também publicou uma série de perguntas + copiados para o arquivo com o nome de dir com ':' caractere no final, a solução não funciona em todos, solução de Paulo está funcionando perfeitamente
jgpATs2w
19

Eu usaria cate com teebase nas respostas que vi em /superuser/32630/parallel-file-copy-from-single-source-to-multiple-targets em vez de cp.

Por exemplo:

cat inputfile | tee outfile1 outfile2 > /dev/null
deter
fonte
1
Um teste superficial que acabei de executar mostra que esse é o melhor desempenho se seus destinos forem unidades físicas diferentes (mantendo duas cópias físicas de uma base de arquivos, como o vídeo de origem de um filme digital).
Curioso
1
Se você estiver usando o bash 3.0 ou superior, poderá usar os intervalos da seguinte forma:cat <inputfile> | tee /path-to-files/outfile{1..4} > /dev/null
Samuel
tee < inputfile outfile1 outfile2 > /dev/nulltambém é um padrão útil, como mostra a resposta de Taywee. Observe o uso do redirecionamento io com '<' para que a tubulação do gato não seja necessária.
Alex Telon
10

Todas essas respostas parecem mais complicadas que o óbvio:

for i in /foo /bar; do cp "$file1" "$i"; done
Waxrat
fonte
um elegante e funcional, para fazer isso em todos os diretórios do diretório atual, pode-se usarfor d in */ ; do cp $file "$i" done
FantomX1
9

ls -db di*/subdir | xargs -n 1 cp File

-bno caso de haver um espaço no nome do diretório, caso contrário, ele será quebrado como um item diferente pelo xargs; este problema ocorreu com a versão echo

thAAAnos
fonte
6

Não usando cp per se, mas ...

Isso surgiu para mim no contexto de copiar muitas imagens Gopro de um cartão SD (lento) para três unidades USB (lentas). Eu queria ler os dados apenas uma vez, porque demorou uma eternidade. E eu queria que fosse recursivo.

$ tar cf - src | tee >( cd dest1 ; tar xf - ) >( cd dest2 ; tar xf - ) | ( cd dest3 ; tar xf - )

(E você pode adicionar mais dessas seções> () se desejar mais saídas.)

Eu não comparei isso, mas é definitivamente muito mais rápido que o cp-in-a-loop (ou várias invocações paralelas de cp).

oggust
fonte
5

Para usar a cópia xargsem diretórios usando curingas no Mac OS, a única solução que funcionou para mim com espaços no nome do diretório é:

find ./fs*/* -type d -print0 | xargs -0 -n 1 cp test 

Onde testestá o arquivo para copiar
e./fs*/* os diretórios para copiar

O problema é que o xargs vê os espaços como um novo argumento, as soluções para alterar o caractere delimitador usando -dou -Einfelizmente não está funcionando corretamente no Mac OS.

MegaCookie
fonte
4

Se você quiser fazer isso sem um comando bifurcado:

tee <inputfile file2 file3 file4 ... >/dev/null

Taywee
fonte
2

Essencialmente equivalente à resposta xargs, mas caso você queira uma execução paralela:

parallel -q cp file1 ::: /foo/ /bar/

Portanto, por exemplo, para copiar o arquivo1 em todos os subdiretórios da pasta atual (incluindo recursão):

parallel -q cp file1 ::: `find -mindepth 1 -type d`

NB: Provavelmente isso só transmite ganhos de velocidade perceptíveis para casos de uso muito específicos, por exemplo, se cada diretório de destino for um disco distinto.

Também é funcionalmente semelhante ao argumento '-P' para xargs.

alainv
fonte
0

Não, você não pode.

Descobri em várias ocasiões que poderia usar essa funcionalidade, por isso criei minha própria ferramenta para fazer isso por mim.

http://github.com/ddavison/branch

bem simples -
branch myfile dir1 dir2 dir3

ddavison
fonte
Muitas vezes, existem cenários em que eu escreveria meu próprio script, mas hoje em dia uso tantas máquinas que manter todas elas sincronizadas parece um grande aborrecimento. Se ao menos houvesse uma maneira de montar um diretório da web na nuvem, /epor exemplo, apenas uma vez em cada máquina, eu poderia escrever minhas próprias ferramentas e mantê-las para sempre.
Evgeni Sergeev
0
ls -d */ | xargs -iA cp file.txt A
Sj Lee
fonte
1
Que tal um pouco de explicação?
mins
Isso realmente funciona, mas uma explicação teria sido ótimo
Ælex
0

Suponha que você queira copiar fileName.txtpara todos os subdiretórios do diretório de trabalho atual.

  1. Obtenha todos os nomes dos subdiretórios lse salve-os em algum arquivo temporário, por exemplo,allFolders.txt

    ls > allFolders.txt
  2. Imprima a lista e passe-a para o comando xargs.

    cat allFolders.txt | xargs -n 1 cp fileName.txt
Devendra Lattu
fonte
0

Outra maneira é usar gato e camiseta da seguinte maneira:

cat <source file> | tee <destination file 1> | tee <destination file 2> [...] > <last destination file>

Eu acho que isso seria bastante ineficiente, pois o trabalho seria dividido entre vários processos (um por destino) e o disco rígido gravaria vários arquivos de uma só vez em diferentes partes do prato. No entanto, se você quiser gravar um arquivo em várias unidades diferentes, esse método provavelmente será bastante eficiente (pois todas as cópias podem ocorrer simultaneamente).

jww
fonte
0

Usando um script bash

DESTINATIONPATH[0]="xxx/yyy"
DESTINATIONPATH[1]="aaa/bbb"
                ..
DESTINATIONPATH[5]="MainLine/USER"
NumberOfDestinations=6

for (( i=0; i<NumberOfDestinations; i++))
    do
        cp  SourcePath/fileName.ext ${DESTINATIONPATH[$i]}

    done
exit
Patrick Manley
fonte
Eu dei um voto negativo. A pergunta solicitou especificamente uma solução sem loop.
Alex Telon
-1

se você deseja copiar várias pastas para várias, pode-se fazer algo assim:

eco dir1 dir2 dir3 | xargs -n 1 cp -r / caminho / toyourdir / {subdir1, subdir2, subdir3}

Isaac
fonte
-1

Se todos os seus diretórios de destino corresponderem a uma expressão de caminho - como se todos fossem subdiretórios path/to-, use-os findem combinação com cp:

find ./path/to/* -type d -exec cp [file name] {} \;

É isso aí.

Mig82
fonte
Eu dei um voto negativo. A pergunta solicitou especificamente uma solução não encontrada.
Alex Telon
Obrigado por ser tão completo @AlexTelon. Acho que perdi esse pedaço. Espero que você também tenha sido consistente e tenha votado negativamente a todas as outras respostas usando o findthread.
Mig82
-2

Se precisar especificar em quais pastas copiar o arquivo, é possível combinar a localização com um ou mais greps. Por exemplo, para substituir quaisquer ocorrências do favicon.ico em qualquer subpasta, você pode usar:

find . | grep favicon\.ico | xargs -n 1 cp -f /root/favicon.ico
Kristofer
fonte
-3

Isso será copiado para os subdiretórios imediatos. Se você quiser ir mais fundo, ajuste o -maxdepthparâmetro.

find . -mindepth 1 -maxdepth 1 -type d| xargs -n 1 cp -i index.html

Se você não deseja copiar para todos os diretórios, esperamos poder filtrar os diretórios nos quais não está interessado. Exemplo de cópia para todas as pastas começando com a

find . -mindepth 1 -maxdepth 1 -type d| grep \/a |xargs -n 1 cp -i index.html

Se você copiar para um conjunto arbitrário / separado de diretórios, precisará da sugestão de Robert Gamble.

Ouriço
fonte
-3

Eu gosto de copiar um arquivo em vários diretórios como tal: cp file1 /foo/; cp file1 /bar/; cp file1 /foo2/; cp file1 /bar2/ E copiar um diretório em outros diretórios: cp -r dir1/ /foo/; cp -r dir1/ /bar/; cp -r dir1/ /foo2/; cp -r dir1/ /bar2/

Eu sei que é como emitir vários comandos, mas funciona bem para mim quando eu quero digitar 1 linha e ir embora por um tempo.

Stace Fauske
fonte
7
Você está respondendo a uma pergunta de 6 anos com 15 outras respostas. Sua resposta precisa ser bem nova. Minha opinião - não é.
Craig S. Anderson
-4

Por exemplo, se você estiver no diretório pai das suas pastas de destino, poderá:

para i em $ (sl); faça cp sourcefile $ i; feito

Behrooz
fonte
A pergunta diz que é possível com um loop for, então isso realmente não adiciona nada.
LJNielsenDk
Votado. Nunca tente analisar a saídals e sempre cite variáveis. for i in ./*; do cp sourcefile "$i"; done
sleblanc