Copier plusieurs fichiers spécifiques d'un dossier à un autre

133

J'ai un grand dossier d'images (en milliers) et j'ai une longue liste de fichiers, par nom de fichier exact, que je dois copier dans un autre dossier. Je souhaite savoir s’il est possible de sélectionner plusieurs fichiers spécifiques dans ce dossier, de les nommer, et de les copier dans un autre dossier à l’aide du terminal, sans les copier individuellement.

Quelqu'un avec trop de pict
la source
Fyi, pour copier des dossiers spécifiques, utilisez:, cp -rp /copying/from/{folder1/,folder2/,folder3/} path/to/folderpest pour copier l'autorisation du dossier.
Raktim Biswas le

Réponses:

179

Copiez simplement plusieurs fichiers à la fois à partir de la ligne de commande

Vous pouvez y parvenir de plusieurs manières. Le plus simple que j'ai vu est d'utiliser ce qui suit.

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

La syntaxe utilise la commande cp suivie du chemin d'accès au répertoire dans lequel se trouvent les fichiers souhaités. Tous les fichiers que vous souhaitez copier sont entourés de crochets et séparés par des virgules.

Assurez-vous de noter qu'il n'y a pas d'espace entre les fichiers. La dernière partie de la commande, /home/usr/destination/est le répertoire dans lequel vous souhaitez copier les fichiers.

ou si tous les fichiers ont le même préfixe mais des terminaisons différentes, vous pouvez faire quelque chose comme ceci:

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

Où fichier1, fichier2, fichier3 et fichier4 seraient copiés.

De la façon dont vous avez formulé la question, je pense que c’est ce que vous recherchez, mais il semble également que vous cherchiez peut-être une commande à lire dans une liste de fichiers et à les copier tous dans un répertoire donné. Si tel est le cas, faites le moi savoir et je modifierai ma réponse.

Traiter les doublons avec python

J'ai donc écrit un petit script en python qui, à mon avis, devrait faire l'affaire. Cependant, je ne suis pas sûr de votre degré de connaissance de python (je ne sais pas du tout), je vais donc essayer d'expliquer comment utiliser ce script du mieux que je peux et s'il vous plaît, posez autant de questions que vous le souhaitez.

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))

Ce script devrait être relativement simple à utiliser. Tout d’abord, copiez le code ci-dessus dans le programme gedit (qui devrait être pré-installé dans Ubuntu) ou dans n’importe quel autre éditeur de texte.

Une fois cette opération terminée, enregistrez le fichier sous le nom move.py dans votre répertoire de base (il peut s’agir de n’importe quel répertoire mais, pour votre facilité d’instruction, il suffit d’utiliser le répertoire de base) ou ajoutez le répertoire dans lequel le fichier se trouve dans votre PATH. Puis cddans votre répertoire personnel (ou le répertoire dans lequel vous avez enregistré move.py) à partir du terminal et tapez la commande suivante:

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

Cela devrait copier tous les fichiers répertoriés du répertoire source dans le répertoire de destination avec les doublons au format pic (1) .jpg, pic (2) .jpg, etc. fichier.txt doit être un fichier qui répertorie toutes les images que vous souhaitez copier avec chaque entrée sur une ligne distincte.

Ce script ne doit en aucun cas affecter le répertoire source. Toutefois, veillez à entrer les chemins d'accès corrects aux répertoires source et de destination. Le pire qui puisse arriver est de copier les fichiers dans le mauvais répertoire.

Remarques

  • Ce script suppose que toutes les images d'origine se trouvent dans le même répertoire. Si vous souhaitez également vérifier les sous-répertoires, vous devez modifier le script.
  • Si vous saisissez un nom de fichier par erreur, le script génère le message d'erreur
    "Le fichier n'existe pas" et vous invite à "appuyer sur la touche Entrée" pour continuer et le script continue à copier le reste de la liste.
  • N'oubliez pas la fin /du chemin d'accès au
    répertoire source et du chemin d'accès au répertoire de destination. Sinon, le script vous créera une erreur.
Bryan
la source
Merci, cela a résolu la plupart de mes problèmes, cependant, certains fichiers apparaissent dans la liste deux fois ou plus. Comment puis-je le faire renommer automatiquement ces doublons? (Oui, j'ai besoin des doublons pour ce que je fais.)
Quelqu'un avec beaucoup trop d'images pict
Les doublons proviennent-ils de différents sous-dossiers ou sont-ils étiquetés avec quelque chose comme file.jpg et file (1) .jpg? sinon, je ne sais pas comment vous avez des fichiers identiques. Pour répondre un peu à votre question, je ne pense pas que vous allez être en mesure de trouver un support simple qui renommera automatiquement les doublons pour vous. Je pense qu'un bash ou un autre type de script devrait être écrit pour obtenir ce type de fonctionnalité. Cependant, j'ai vu des commandes d'une ligne assez ridicules, donc peut-être qu'un assistant Linux pourrait apparaître et fournir la réponse.
Bryan
Je n'ai à l'origine qu'un seul de chaque fichier, cependant les noms des fichiers sont dans la liste deux fois ou plus. Plus ou moins ce que j'ai besoin de faire pour essayer de placer un fichier dans le nouveau dossier et qu'il existe déjà un fichier portant ce nom. J'ai besoin qu'il ajoute un (2) ou plus à la fin du nom de fichier. et placez-le.
Quelqu'un avec beaucoup trop de pict
Je veux juste suggérer de mettre l'accent sur la partie sur l'absence d'espaces dans la liste des fichiers à copier. S'il y a des espaces, même entre les fichiers {foo, bar, ..}, la commande ne fonctionnera pas.
Franksands
Pour ceux qui recherchent des raccourcis supplémentaires, vous pouvez utiliser la substitution de commande pour remplacer le chemin absolu des fichiers, c.-à-d. cp $(pwd)/{file1,file2} /path/to/dst/Ou cp $(pwd)/{file1,file2} $(pwd)/{renamed1,renamed2}, etc.
baelx
50

Il me manque peut-être un détail de votre question, mais les réponses fournies semblent excessives. Si vous voulez une solution en ligne de commande et non un script, pourquoi pas:

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

La bonne chose à faire de cette façon est que vous pouvez compléter les noms de fichiers

Ross Allen
la source
5
Cela retourne une "option illégale --t" dans macOS Sierra
geoyws
Excellente réponse, beaucoup plus simple. @geoyws Peut-être que c'est une chose POSIX ou GNU que la version d'Apple n'a pas. Cela fonctionne bien pour moi sous Debian Linux ou Windows avec MSYS2.
underscore_d
belle suggestion! travaillé sous linux.
Edu Ruiz
brew install coreutilsalors vous pouvez obtenir des trucs de gnou habituels avec gpréfixe. Donc ça va êtregcp -t ....
T.Chmelevskij
Mac OS utilise la version BSD de cp, et en particulier, ni OpenBSD ni FreeBSD ne disposent de cette option, alors oui - cela est cp spécifique à GNU . Ce n'est pas non plus spécifié par la norme POSIX . Comme il s'agit d'un site spécifique à Ubuntu, c'est acceptable, mais pour porter des scripts entre des systèmes d'exploitation, il est préférable de s'en tenir à la norme POSIX
Sergiy Kolodyazhnyy
7

Voici une solution pure bash. Il lit les noms de fichier d'un fichier d'entrée (un par ligne) et les copie, en renommant les doublons.

#!/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

Enregistrez ce script dans un dossier de votre $PATHet appelez-le avec la liste des chemins en entrée:

auto_copy.sh < file_paths.txt

Vous pouvez également exécuter le tout en tant que commande du 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;
terdon
la source
1

Selon la description de la question, ma compréhension est la suivante:

  • il y a une liste de fichiers, probablement un fichier texte input.txt
  • la liste contient uniquement les noms de fichiers
  • il y a un répertoire particulier où ces noms de fichiers sont situés.

Ainsi, on peut utiliser la commande suivante:

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

Explication:

  • -I % spécifie le symbole du fichier en cours de traitement à utiliser dans la commande
  • --arg-file=input.txt spécifie de prendre les arguments à commander input.txt
  • cp /path/to/origin_dir/% /path/to/destination/effectuera la cpcommande /path/to/origin_dir/%en remplaçant par /path/to/origin_dir/et le nom du fichier en cours de traitement.

Exemple pratique:

$ 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
Sergiy Kolodyazhnyy
la source