Copiar múltiples archivos específicos de una carpeta a otra


133

Tengo una gran carpeta de imágenes (miles) y tengo una larga lista de archivos, por nombre exacto, que necesito copiar en otra carpeta. ¿Quiero saber si hay una manera de seleccionar varios archivos específicos de esta carpeta, por nombre, y copiarlos en otra carpeta, usando el terminal, sin copiarlos individualmente?


Fyi, para copiar carpetas específicas use:, cp -rp /copying/from/{folder1/,folder2/,folder3/} path/to/folderdonde pes para copiar el permiso de la carpeta.
Raktim Biswas

Respuestas:


179

Simplemente copie varios archivos a la vez desde la línea de comando

Hay varias formas de lograr esto. Lo más fácil que he visto es usar lo siguiente.

cp /home/usr/dir/{file1,file2,file3,file4} /home/usr/destination/

La sintaxis utiliza el comando cp seguido de la ruta al directorio en el que se encuentran los archivos deseados con todos los archivos que desea copiar envueltos entre paréntesis y separados por comas.

Asegúrese de tener en cuenta que no hay espacios entre los archivos. La última parte del comando, /home/usr/destination/es el directorio en el que desea copiar los archivos.

o si todos los archivos tienen el mismo prefijo pero diferentes finales, podría hacer algo como esto:

cp /home/usr/dir/file{1..4} ./

Donde se copiarían file1, file2, file3 y file4.

Por cómo redactó la pregunta, creo que esto es lo que está buscando, pero también parece que podría estar buscando un comando para leer de una lista de archivos y copiarlos a un directorio determinado. Si ese es el caso, hágamelo saber y editaré mi respuesta.

Manejo de duplicados con python

Así que escribí un pequeño script de Python que creo que debería hacer el trabajo. Sin embargo, no estoy seguro de qué tan bien versado está en Python (si está versado en absoluto), así que intentaré explicar cómo usar este script lo mejor que pueda y le haré todas las preguntas que necesite.

import os,sys,shutil
### copies a list of files from source. handles duplicates.
def rename(file_name, dst, num=1):
    #splits file name to add number distinction
    (file_prefix, exstension) = os.path.splitext(file_name)
    renamed = "%s(%d)%s" % (file_prefix,num,exstension)

    #checks if renamed file exists. Renames file if it does exist.
    if os.path.exists(dst + renamed):
        return rename(file_name, dst, num + 1)
    else:
        return renamed

def copy_files(src,dst,file_list):
    for files in file_list:
        src_file_path = src + files
        dst_file_path = dst + files
        if os.path.exists(dst_file_path):
            new_file_name =  rename(files, dst)
            dst_file_path = dst + new_file_name

        print "Copying: " + dst_file_path
        try:
            shutil.copyfile(src_file_path,dst_file_path)
        except IOError:
            print src_file_path + " does not exist"
            raw_input("Please, press enter to continue.")

def read_file(file_name):
    f = open(file_name)
    #reads each line of file (f), strips out extra whitespace and 
    #returns list with each line of the file being an element of the list
    content = [x.strip() for x in f.readlines()]
    f.close()
    return content

src = sys.argv[1]
dst = sys.argv[2]
file_with_list = sys.argv[3]

copy_files(src,dst,read_file(file_with_list))

Este script debe ser relativamente simple de usar. En primer lugar, copie el código anterior en el programa gedit (debe estar preinstalado en Ubuntu) o en cualquier otro editor de texto.

Una vez que se haya completado, guarde el archivo como move.py en su directorio de inicio (puede ser cualquier directorio, pero para facilitar la instrucción, simplemente usemos el directorio de inicio) o agregue el directorio en el que se encuentra el archivo a su RUTA. Luego cda su directorio de inicio (o cualquier directorio en el que haya guardado move.py) desde la terminal y escriba el siguiente comando:

python move.py /path/to/src/ /path/to/dst/ file.txt

Esto debería copiar todos los archivos que se enumeran desde el directorio de origen al directorio de destino con duplicados tomando el formato pic (1) .jpg, pic (2) .jpg y así sucesivamente. file.txt debe ser un archivo que enumere todas las imágenes que le gustaría copiar con cada entrada en su propia línea separada.

De ninguna manera este script debería afectar el directorio de origen, sin embargo, solo asegúrese de ingresar las rutas correctas al directorio de origen y de destino y lo peor que podría suceder es que copie los archivos en el directorio incorrecto.

Notas

  • Este script supone que todas las imágenes originales están en el mismo directorio. Si desea que también verifique los subdirectorios, deberá modificar el script.
  • Si accidentalmente escribe mal el nombre de un archivo, el script escupirá el error
    "el archivo no existe" y le pedirá que "presione enter" para continuar y el script continuará copiando el resto de la lista.
  • No olvide el final /tanto en la ruta al
    directorio de origen como en la ruta al directorio de destino. De lo contrario, el script le devolverá un error.

Gracias, eso resolvió la mayor parte de mi problema, sin embargo, algunos archivos aparecen en la lista dos veces o más. ¿Cómo puedo hacer que renombre automáticamente estos duplicados? (Sí, necesito los duplicados para lo que estoy haciendo.)
Alguien con demasiadas imágenes el

¿Son los duplicados de diferentes subcarpetas o están etiquetados como file.jpg y file (1) .jpg? de lo contrario, no estoy seguro de cómo tiene archivos que sean idénticos. Para responder un poco a su pregunta, no creo que pueda encontrar un simple en línea que renombre automáticamente los duplicados para usted. Creo que una bash o algún otro tipo de script debería escribirse para obtener ese tipo de funcionalidad. Sin embargo, he visto algunos comandos de una línea bastante ridículos, por lo que tal vez algún asistente de Linux pueda aparecer y proporcionar la respuesta.
Bryan

Solo tengo uno de cada archivo originalmente, sin embargo, los nombres de los archivos están en la lista dos veces o más. Más o menos lo que necesito que haga, cuando intento colocar un archivo en la nueva carpeta, y un archivo con ese nombre ya existe, necesito que agregue un (2) más o menos al final del nombre del archivo y colocarlo
Alguien con demasiadas imágenes el

Solo quiero sugerir enfatizar la parte de no tener espacios en la lista de archivos para copiar. Si hay espacios, incluso entre los archivos {foo, bar, ..}, el comando no funcionará.
franksands

Para aquellos que buscan más accesos directos, puede hacer uso de la sustitución de comandos para reemplazar la ruta absoluta de los archivos, es decir , cp $(pwd)/{file1,file2} /path/to/dst/o cp $(pwd)/{file1,file2} $(pwd)/{renamed1,renamed2}, etc.
baelx

50

Quizás me falta un detalle de su pregunta, pero las respuestas dadas parecen excesivas. Si desea una solución de línea de comando y no un script, por qué no:

cd /path/to/src/
cp -t /path/to/dst/ file1 file2 file3 ...

Lo bueno de hacerlo de esta manera es que puedes completar con tabulación los nombres de archivo


55
Esto devuelve una "opción ilegal --t" en macOS Sierra
geoyws

Gran respuesta, mucho más simple. @geoyws Quizás sea una cosa POSIX o GNU que la versión de Apple no tiene. Me funciona bien en Debian Linux o Windows con MSYS2.
underscore_d

buena sugerencia! Trabajó en Arch Linux.
Edu Ruiz

brew install coreutilsentonces puedes obtener cosas habituales de gnu con gprefijo. Así serágcp -t ....
T.Chmelevskij

Mac OS usa la versión BSD de cp, y particularmente ni OpenBSD ni FreeBSD tienen esa opción, así que sí, esto es cp específico de GNU . Tampoco está especificado por el estándar POSIX . Dado que este es un sitio específico de Ubuntu, esto es aceptable, pero para portar scripts entre sistemas operativos es mejor atenerse al estándar POSIX
Sergiy Kolodyazhnyy

7

Aquí hay una solución de bash puro. Leerá los nombres de archivo de un archivo de entrada (uno por línea) y copiará cada uno de ellos, renombrando duplicados.

#!/usr/bin/env bash

## The destination folder where your files will
## be copied to.
dest="bar";

## For each file path in your input file
while read path; do 
    ## $target is the name of the file, removing the path. 
    ## For example, given /foo/bar.txt, the $target will be bar.txt.
    target=$(basename "$path"); 
    ## Counter for duplicate files
    c=""; 
    ## Since $c is empty, this will check if the
    ## file exists in target.
    while [[ -e "$dest"/"$target"$c ]]; do
        echo "$target exists"; 
        ## If the target exists, add 1 to the value of $c
        ## and check if a file called $target$c (for example, bar.txt1)
        ## exists. This loop will continue until $c has a value
        ## such that there is no file called $target$c in the directory.
        let c++; 
        target="$target"$c; 
    done; 
    ## We now have everything we need, so lets copy.
    cp "$path" "$dest"/"$target"; 
done

Guarde este script en una carpeta en su $PATHy llámelo con la lista de rutas como entrada:

auto_copy.sh < file_paths.txt

También puede ejecutar todo como un comando desde la terminal:

while read path; do 
   target=$(basename "$path"); 
   c=""; 
   while [[ -e bar/"$target"$c ]]; do 
    echo "$target exists"; 
    let c++; 
    target="$target"$c; 
   done; 
   cp "$file" bar/"$target"; 
done < file_names;

1

Según la descripción de la pregunta, entiendo que:

  • hay una lista de archivos, presumiblemente un archivo de texto input.txt
  • la lista contiene solo nombres de archivos
  • Hay un directorio particular donde se encuentran estos nombres de archivo.

Por lo tanto, uno puede hacer uso del siguiente comando:

xargs -I % --arg-file=input.txt cp  /path/to/origin_dir/%  /path/to/destination

Explicación:

  • -I % especifica el símbolo para el archivo procesado actualmente que se utilizará dentro del comando
  • --arg-file=input.txt especifica tomar argumentos para ordenar desde input.txt
  • cp /path/to/origin_dir/% /path/to/destination/ejecutará el cpcomando con /path/to/origin_dir/%ser reemplazado por /path/to/origin_dir/y el nombre del archivo procesado actualmente.

Ejemplo práctico:

$ cat input.txt
file2.txt
file1.txt
file3.txt
$ ls ./docs
file1.txt  file2.txt  file3.txt
$ xargs -I % --arg-file=input.txt cp ./docs/% ./docs_destination/
$ ls ./docs_destination/
file1.txt  file2.txt  file3.txt
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.