Copiar lista de archivos

35

Tengo una lista de archivos separados por espacios en un archivo list.txt. Me gustaría copiarlos a una nueva carpeta.

Traté de hacer:

cp `cat list.txt` new_folder

Pero no funcionó.

Cómo harías esto ?

Actualizar:

Gracias por todas sus respuestas muy interesantes. No pedí mucho :)

Después de haber probado la solución anterior por segunda vez, parece que se cpimprimió la ayuda de uso porque la carpeta new_folderaún no existía. Lo siento, parece ser un error estúpido ... Cuando creo la carpeta antes, funciona.

Sin embargo, he aprendido mucho de todas sus respuestas y soluciones, gracias por el tiempo que toma escribirlas.

Klaus
fuente
Permítanme aclarar una cosa: ¿la lista tiene todos los nombres de archivo en una línea, separados solo por un espacio? ¿O los nombres están cada uno en una línea separada?
Telémaco el
Todo en una cal, separados por un espacio. La solución de Doug funcionó :) Gracias por la respuesta.
Klaus
Eso es divertido ... Probé mi solución con una línea en la que cada nombre estaba en una línea separada.
Doug Harris el
"no funcionó" no es muy significativo. Exactamente cómo no funcionó. Funciona bien para mí.
Pausado hasta nuevo aviso.
Lo sentimos: mostró ayuda para el uso de cp. Vea mi actualización arriba.
Klaus

Respuestas:

34

Intenta usar xargs:

cat list.txt | xargs -J % cp % new_folder

Actualizar:

Hice esto en OS X, que tiene una versión diferente a las versiones de GNU / Linux. El xargsque proviene de GNU findutils no tiene -Jpero tiene uno -Ique es similar (como señaló Dennis Williamson en un comentario). La versión OS X de xargs tiene ambos -Iy -Jtienen comportamientos ligeramente diferentes: cualquiera funcionará para esta pregunta original.

$ cat list.txt
one
two.txt
three.rtf

$ cat list.txt | xargs -J % echo cp % new_folder
cp one two.txt three.rtf new_folder

$ cat list.txt | xargs -I % echo cp % new_folder
cp one new_folder
cp two.txt new_folder
cp three.rtf new_folder
Doug Harris
fuente
3
Mi xargsno tiene -Jlo -Ique parece hacer lo mismo. ¿Qué versión xargsy qué sistema operativo / distribución tienes?
Pausado hasta nuevo aviso.
Probé esto en Mac OS X 10.6 (también conocido como leopardo de las nieves), por lo que es cualquier versión de xargs que se envíe con el sistema operativo. La ejecución xargs --versiondevuelve un mensaje de error de uso. Es probable que sea una versión BSD de xargs. El uso de -Iy -Json sutilmente diferentes. Actualizaré mi respuesta con ejemplos bien formateados.
Doug Harris
Sí, estoy trabajando con Mac OSX 10.6. Gracias por las precisiones sobre -Jy -I:)
Klaus
Es un buen consejo para usar echo para verificar sus comandos antes de ejecutarlos.
Liam
1
Usando el mismo comando anterior solo con los cambios necesarios, ¿cómo copio los archivos junto con la creación de sus directorios y subdirectorios, separados por una barra diagonal?
Vicky Dev
54

No es necesario caten absoluto:

xargs -a list.txt cp -t new_folder

O usando opciones largas:

xargs --arg-file=list.txt cp --target-directory=new_folder

Aquí hay algunas versiones de shell. Tenga en cuenta que algunas variables no están entre comillas o los forbucles se usan específicamente porque el OP especificó que los nombres de los archivos están delimitados por espacios. Algunas de estas técnicas no funcionarán para la entrada de nombre de archivo por línea en la que los nombres de archivo contienen espacios en blanco.

Golpetazo:

for file in $(<list.txt); do cp "$file" new_folder; done

o

cp $(<list.txt) new_folder

sh (o Bash):

# still no cat!
while read -r line; do for file in $line; do cp "$file" new_folder; done; done < list.txt

o

# none here either
while read -r line; do cp $line new_folder; done < list.txt

o

# meow
for file in $(cat list.txt); do cp "$file" new_folder; done

o

# meow
cp $(cat list.txt) new_folder
Pausado hasta nuevo aviso.
fuente
pregunta novata: ¿por qué se -tnecesita en xargs -a list.txt cp -t new_folder?
Yibo Yang
1
@YiboYang: El -tes una opción de cp. Copia todos los argumentos de origen en el directorio de destino especificado. Aquí, permite especificar el objetivo antes que la fuente que agrega el xargscomando.
Pausado hasta nuevo aviso.
Esto es útil, pero ¿qué sucede si list.txt contiene una ruta de archivos y carpetas mixtas? En ese caso, el comando no funciona correctamente. Informa "omitiendo el directorio ..." y si se especifica -R en el comando cp, se informa el error "no es un directorio" tan pronto como se encuentra el primer archivo de la lista.
Bemipefe
7

Tuve una respuesta vergonzosamente redonda aquí antes, pero la respuesta de Denis me recordó que me perdí lo más básico. Entonces, borré mi respuesta original. Pero como nadie ha dicho esto tan básico, creo que vale la pena ponerlo aquí.

La pregunta original es "Tengo un archivo de texto con una lista de nombres de archivos separados por espacios. Cómo puedo copiarlos en un directorio de destino". Al principio, esto puede parecer complicado o complicado, porque cree que de alguna manera tiene que extraer los elementos del archivo de una manera específica. Sin embargo, cuando el shell procesa una línea de comando, lo primero que hace es separar la lista de argumentos en tokens y (aquí está el bit que nadie ha dicho directamente) separa los tokens . (Las nuevas líneas también separan los tokens, razón por la cual la prueba de Doug Harris con una lista separada por una nueva línea tuvo el mismo resultado). Es decir, el shell espera y ya puede manejar una lista separada por espacios.

Entonces, todo lo que necesita hacer aquí es colocar la lista separada por espacios (que ya tiene) en el lugar correcto en su comando. Su comando es una variación de esto:

cp file1 file2 file3...file# target

El único inconveniente es que desea obtener la lista de archivos 1 a # de su archivo de texto.

Como Dennis señala en su comentario, su intento original ( cpcat list.txt new_folder) ya debería haber funcionado. ¿Por qué? Porque el comando interno cat list.txtes procesado primero por el shell y se expande en file1 file2 file3...file#, que es exactamente lo que el shell espera y quiere en esa parte del comando. Si no funcionó, (1) tenía un error tipográfico o (2) sus nombres de archivo eran algo extraños (tenían espacios u otros caracteres inusuales).

La razón por la que todas las respuestas de Dennis funcionan es simplemente que proporcionan la lista necesaria de archivos para cptrabajar, colocando esa lista donde pertenece en el comando completo. Nuevamente, el comando en sí es esto en estructura:

cp list-of-files target_directory

Es fácil ver cómo todo esto se combina en esta versión:

cp $(<list.txt) new_folder

$()hace que el shell ejecute el comando dentro de los paréntesis y luego sustituya su salida en ese punto en la línea más grande. Entonces el shell recorre la línea como un todo. Por cierto, $()es una versión más moderna de lo que ya estaba haciendo con backticks (`). Siguiente: <es un operador de redirección de archivos. Le dice al shell que descargue el contenido de list.txtla entrada estándar. Como el $()bit se procesa primero, esto es lo que sucede en etapas:

  1. cp $(<list.txt) new_folder # split line into three tokens: cp, $(<list.txt), new_folder
  2. cp file1 file2 file3...file# new_folder # substitute result of $(<list.txt) into the larger command

Obviamente, el paso 2 es simplemente el cpcomando normal que deseabas.

Me doy cuenta de que estoy golpeando mucho a este caballo (quizás muy muerto), pero creo que vale la pena hacerlo. Comprender exactamente cómo el shell procesa un comando puede ayudarlo a escribirlo mejor y simplificar mucho. También le mostrará dónde es probable que se oculten los problemas. En este caso, por ejemplo, mi primera pregunta debería haber sido sobre nombres de archivos divertidos o un posible error tipográfico. No se necesitaban acrobacias.

Telémaco
fuente
@Klaus De nada. Para ser sincero, estaba molesto conmigo mismo después de leer la respuesta de Dennis y darme cuenta de que me perdí por completo la parte clave del problema. La solución que te gusta es a partir de ahí también.
Telémaco el
Esta es una respuesta súper antigua, pero si necesita volver a crear la estructura de la carpeta, necesita el --parentsindicador. Puede hacerlo detallado -vpara obtener un registro de lo que se copió. Si desea mantener los permisos, necesita la bandera -ao -p. Es decir, cp --parents -av $(<list.txt) new_folder. Todo esto supone que su lista de archivos son realmente todos los archivos, de lo contrario, es posible que también necesite -rque se repita el indicador.
dhaupin
@dhaupin En realidad, el OP afirma que estaba en macOS. Entonces, por lo que vale, la --parentsbandera no existe allí. Su versión (derivada de BSD) cpsolo ofrece opciones cortas, no opciones largas al estilo GNU. Para un estilo BSD cp, el indicador de copia recursiva es mayúscula -R, no minúscula.
Telémaco