Copiando un solo archivo a múltiples directorios usando cp

12

Esta pregunta es una secuela de mi pregunta anterior, Creación de numerosos directorios usandomkdir .

Estoy usando el bashcaparazón. He creado cincuenta directorios, cada uno comenzando con el prefijo "s", usando el comando:

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

que rellena el segundo dígito con ceros. Es decir, los directorios que obtengo son de la forma s01, s02, ..., s49, s50.

Ahora me gustaría usar cppara copiar un solo archivo (por ejemplo test.txt) en cada uno de los cincuenta directorios. ¿Es posible hacer esto de una manera análoga a la anterior? Por ejemplo, ¿funcionaría lo siguiente? Soy relativamente nuevo en Unix / Linux, por lo que no quiero probar esto hasta que alguien me indique que es seguro.

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

Sin embargo, al mirar la manpágina cp, no parece que sea cpcompatible con múltiples destinos como este:

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.
Andrés
fuente

Respuestas:

7

Si desea utilizar la salida de su comando para copiar el archivo a cada directorio utilizando cp, siempre puede canalizarlo a xargs:

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

No debería haber ninguna preocupación sobre la seguridad de analizar la salida, ya que conoce su formato y contenido de antemano; el riesgo de encontrar metacaracteres y espacio en los nombres de archivo no es realmente un problema aquí.

Alternativamente, suponiendo que los directorios ya existan, puede intentar algo como:

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

o sin tubo:

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

Los últimos dos comandos encontrarán cualquier archivo en el directorio actual y cp test.txten ellos. La -maxdepth 1opción evitará cualquier subdirectorio que reciba el archivo también. Tenga en cuenta que 's[0-9][0-9]'coincide con sseguido de dos dígitos cualesquiera, lo que significa que si por alguna razón tiene s99en el cwd, también recibirá una copia de test.txt.

tojrobinson
fuente
8

También puede dejar que el shell haga las iteraciones con un forbucle. Esta es la forma más básica que no depende de herramientas externas como parallelo xargs, y me resulta más fácil de entender:

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

Hay un millón de otras formas de escribir esto, por ejemplo:

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

Si desea verificar qué se ejecutará antes de hacerlo, puede hacer algo como anteponer los comandos echo, que imprimirá la línea en lugar de ejecutarla:

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

salidas:

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

También podría usar GNU paralelo . Suponiendo que está en el directorio que contiene text.txt y sus 50 directorios se encuentran en /my/50dirs/path(como /my/50dirs/path/s01, /my/50dirs/path/s02etc.), ejecutaría:

seq -w 01 50 | parallel -j1 cp text.txt /my/50dirs/path/s{}
revs don_crissti
fuente
2
Mejor hacer eso parallel -j1, de lo contrario habrá un trabajo por núcleo, y en una máquina multinúcleo los trabajos competirán por IO.
Gilles 'SO- deja de ser malvado'