Cómo copiar un archivo a múltiples directorios usando el comando gnu cp

210

¿Es posible copiar un solo archivo a múltiples directorios usando el comando cp?

Intenté lo siguiente, que no funcionó:

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

Sé que es posible usar un bucle for o find. Pero, ¿es posible usar el comando gnu cp?

Tom Feiner
fuente

Respuestas:

106

No, cppuede copiar múltiples fuentes pero solo se copiará en un solo destino. Debe hacer arreglos para invocar cpvarias veces, una vez por destino, para lo que desea hacer; usando, como dices, un bucle u otra herramienta.

sombra de Luna
fuente
¡Gracias por la respuesta! Ahora que lo pienso un poco más, sin banderas adicionales (que no existen), cp no sabrá cuál es la fuente y cuál es el directorio DEST.
Tom Feiner,
10
Esta no es la respuesta correcta. Por favor, vea la respuesta de Robert Gamble.
PlagueHammer
23
@Nocturne: ¿qué parte de lo que dije es incorrecta? Robert da un ejemplo del uso de otra herramienta para invocar cp varias veces, como sugiero. Hay muchas soluciones posibles que implican el uso de otras herramientas o construcciones para hacer eso, pero el OP indicó que ya sabía que es posible.
sombra de luna
2
Triste, sería genial para cp (y scp) admitir esa función. Sin embargo, podemos usar tee para hacer la división. superuser.com/questions/32630/…
Simon
44
@moonshadow: Por supuesto, tu respuesta es correcta. Creo que PlagueHammer quiere decir que en este contexto la otra respuesta es más útil. ¿Quizás también puede incluir algo así en su respuesta?
Pacífica
585

No puedes hacer esto cpsolo, pero puedes combinarlo cpcon xargs:

echo dir1 dir2 dir3 | xargs -n 1 cp file1

Copiará file1a dir1, dir2y dir3. xargsllamará cp3 veces para hacer esto, vea la página del manual xargspara más detalles.

Robert Gamble
fuente
3
Más información sobre xargs: cyberciti.biz/faq/…
Chris Bier
24
@Simon ¿cómo es eso? "No se puede hacer esto cpsolo". El hecho de que la respuesta haya intentado ser útil al sugerir otra forma no significa que la pregunta no haya sido respondida.
Nicole
3
@NickC El autor de la pregunta especificó: "Sé que es posible usar un bucle for o find. ¿Pero es posible usar el comando gnu cp?" La buena respuesta es la aceptada.
Simon
25
Estipular que las respuestas sean aceptadas en función de si técnicamente responden a la pregunta sería insufriblemente pedante y no realmente útil.
Backgammon
44
¡Muy útil! Para otros principiantes como yo: no puedes usar regex con cp, pero puedes hacerlo en la primera parte de este comando (por ejemplo echo dir[1-3] | xargs -n 1 cp filename).
Jason
77

Los comodines también funcionan con el código Roberts

echo ./fs*/* | xargs -n 1 cp test 
Pablo
fuente
y todo el comentario ... Por ejemplo, para mover un archivo propiedad de root (un enlace simbólico en realidad) que estaba en mi escritorio al escritorio de todos los usuarios, primero tuve que sudo su (no funcionó) y luego usé: echo / home / * / Escritorio / | xargs -n 1 cp -av / home / myusername / Desktop / file.
David G
19

Por lo que puedo ver, puedes usar lo siguiente:

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

La -iopción de cpcomando significa que se le preguntará si desea sobrescribir un archivo en el directorio actual con el file.dat. Aunque no es una solución completamente automática, funcionó para mí.

Evgeny
fuente
1
Si bien es bueno haber agregado la -iprotección, ¿eso no te incitará a escribir más de cada archivo? en lugar de copiar a los directorios?
Hedgehog
1
@Hedgehog Bueno, creo que este comando es útil cuando hay un archivo en el directorio y uno quiere copiarlo en subdirectorios del directorio. En este caso, un archivo puede sobrescribirse solo una vez. Gracias por tu pregunta!
Evgeny
2
Para mí, imprimió una serie de cp: overwritepreguntas, pero no tuve que responder ninguna de ellas, y no sobrescribió los archivos.
Evgeni Sergeev
También imprimí una serie de preguntas + copié en el archivo con el nombre de dir con el carácter ':' al final, no hay ninguna solución que funcione, la solución de Paul funciona perfectamente
jgpATs2w
19

Lo usaría caty teebasándome en las respuestas que vi en /superuser/32630/parallel-file-copy-from-single-source-to-multiple-targets en lugar de cp.

Por ejemplo:

cat inputfile | tee outfile1 outfile2 > /dev/null
determinar
fuente
1
Una prueba superficial que acabo de ejecutar muestra que este es el mejor desempeño si sus destinos son unidades físicas diferentes (mantener dos copias físicas de una base de archivos como video fuente para una película digital).
curioso
1
Si está utilizando bash 3.0 o superior, puede usar rangos de la siguiente manera:cat <inputfile> | tee /path-to-files/outfile{1..4} > /dev/null
Samuel
tee < inputfile outfile1 outfile2 > /dev/nullTambién es un patrón útil como lo muestra la respuesta de Taywee. Tenga en cuenta el uso de io-redirección con '<' para que no se necesite la tubería de cat.
Alex Telon
10

Todas estas respuestas parecen más complicadas que las obvias:

for i in /foo /bar; do cp "$file1" "$i"; done
Waxrat
fuente
un elegante y funcional, para hacerlo para todos los directorios en el directorio actual, uno puede usarfor d in */ ; do cp $file "$i" done
FantomX1
9

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

-b en caso de que haya un espacio en el nombre del directorio, de lo contrario, xargs lo dividirá como un elemento diferente, tuvo este problema con la versión echo

THAAAnos
fuente
6

No usa cp per se, pero ...

Esto se me ocurrió en el contexto de copiar muchas imágenes de Gopro de una tarjeta SD (lenta) a tres unidades USB (lentas). Solo quería leer los datos una vez, porque me llevó una eternidad. Y lo quería recursivo.

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

(Y puede agregar más de esas secciones> () si desea más salidas).

No lo he comparado, pero definitivamente es mucho más rápido que cp-in-a-loop (o un montón de invocaciones de cp paralelas).

oggust
fuente
5

Para usar la copia con xargsdirectorios usando comodines en Mac OS, la única solución que me funcionó con espacios en el nombre del directorio es:

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

¿Dónde testestá el archivo para copiar
y./fs*/* los directorios para copiar?

El problema es que xargs ve los espacios como un nuevo argumento, las soluciones para cambiar el carácter delimitador usando -do -Edesafortunadamente no funciona correctamente en Mac OS.

MegaCookie
fuente
4

Si quieres hacerlo sin un comando bifurcado:

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

Taywee
fuente
2

Esencialmente equivalente a la respuesta xargs, pero en caso de que desee una ejecución paralela:

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

Entonces, por ejemplo, para copiar el archivo1 en todos los subdirectorios de la carpeta actual (incluida la recursividad):

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

NB: Esto probablemente solo transmite ganancias de velocidad notables para casos de uso muy específicos, por ejemplo, si cada directorio de destino es un disco distinto.

También es funcionalmente similar al argumento '-P' para xargs.

alainv
fuente
0

No, no puedes.

En varias ocasiones descubrí que podía usar esta funcionalidad, así que hice mi propia herramienta para hacer esto por mí.

http://github.com/ddavison/branch

bastante simple -
branch myfile dir1 dir2 dir3

ddavison
fuente
A menudo hay escenarios en los que escribiría mi propio script, pero tiendo a usar tantas máquinas hoy en día que mantenerlas todas sincronizadas parece una gran molestia. Si solo hubiera una manera de montar un directorio web en la nube, /epor ejemplo, solo una vez en cada máquina, entonces podría escribir mis propias herramientas y guardarlas para siempre.
Evgeni Sergeev
0
ls -d */ | xargs -iA cp file.txt A
Sj Lee
fuente
1
¿Qué tal un poco de explicación?
minutos
Esto realmente funciona, pero una explicación hubiera sido genial
Ælex
0

Suponga que desea copiar fileName.txta todos los subdirectorios dentro del directorio de trabajo actual.

  1. Obtenga todos los nombres de subdirectorios lsy guárdelos en algún archivo temporal, por ejemplo,allFolders.txt

    ls > allFolders.txt
  2. Imprima la lista y páselo al comando xargs.

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

Otra forma es usar cat y tee de la siguiente manera:

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

Sin embargo, creo que esto sería bastante ineficiente, ya que el trabajo se dividiría entre varios procesos (uno por destino) y el disco duro escribiría varios archivos a la vez en diferentes partes del plato. Sin embargo, si desea escribir un archivo en varias unidades diferentes, este método probablemente sería bastante eficiente (ya que todas las copias podrían ocurrir simultáneamente).

jww
fuente
0

Usando un 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
fuente
Le di un voto negativo a esto. La pregunta pedía específicamente una solución sin bucle.
Alex Telon
-1

Si desea copiar varias carpetas en varias carpetas, puede hacer algo como esto:

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

Isaac
fuente
-1

Si todos sus directorios de destino coinciden con una expresión de ruta, como si fueran todos subdirectorios de path/to, entonces solo use finden combinación con cpesto:

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

Eso es.

Mig82
fuente
Le di un voto negativo a esto. La pregunta solicitó específicamente una solución de no encontrar.
Alex Telon
Gracias por ser tan minucioso @AlexTelon. Supongo que me perdí un poco. Espero que también haya sido coherente y haya votado negativamente a cualquier otra respuesta usando finden hilo.
Mig82
-2

Si necesita ser específico en qué carpetas copiar el archivo, puede combinar encontrar con uno o más greps. Por ejemplo, para reemplazar cualquier ocurrencia de favicon.ico en cualquier subcarpeta, puede usar:

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

Esto se copiará en los subdirectorios inmediatos, si desea profundizar, ajuste el -maxdepthparámetro.

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

Si no desea copiar a todos los directorios, es de esperar que pueda filtrar los directorios que no le interesan. Ejemplo de copia a todas las carpetas que comienzan con a

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

Si copia a un conjunto de directorios arbitrario / disjunto, necesitará la sugerencia de Robert Gamble.

Erizo
fuente
-3

Me gusta copiar un archivo en múltiples directorios como tal: cp file1 /foo/; cp file1 /bar/; cp file1 /foo2/; cp file1 /bar2/ Y copiar un directorio en otros directorios: cp -r dir1/ /foo/; cp -r dir1/ /bar/; cp -r dir1/ /foo2/; cp -r dir1/ /bar2/

Sé que es como emitir varios comandos, pero funciona bien para mí cuando quiero escribir 1 línea y alejarme por un tiempo.

Stace Fauske
fuente
77
Estás respondiendo una pregunta de 6 años con otras 15 respuestas. Tu respuesta debe ser bastante novedosa. Mi opinión, no lo es.
Craig S. Anderson el
-4

Por ejemplo, si está en el directorio principal de sus carpetas de destino, puede hacer:

para i en $ (ls); hacer cp sourcefile $ i; hecho

Behrooz
fuente
La pregunta dice que es posible con un bucle for, por lo que esto realmente no agrega nada.
LJNielsenDk
Voto negativo Nunca intente analizar la salida dels , y siempre cite las variables. for i in ./*; do cp sourcefile "$i"; done
sleblanc