Kopieren mehrerer bestimmter Dateien von einem Ordner in einen anderen

133

Ich habe einen großen Ordner mit Bildern (Tausende) und eine lange Liste von Dateien mit genauem Dateinamen, die ich in einen anderen Ordner kopieren muss. Ich möchte wissen, ob es eine Möglichkeit gibt, mehrere bestimmte Dateien aus diesem Ordner nach Namen auszuwählen und sie mit dem Terminal in einen anderen Ordner zu kopieren, ohne sie einzeln zu kopieren.

Jemand mit viel zu vielen Bildern
quelle
Fyi, verwenden Sie zum Kopieren bestimmter Ordner: cp -rp /copying/from/{folder1/,folder2/,folder3/} path/to/folder, wo pzum Kopieren der Ordner Erlaubnis ist.
Raktim Biswas

Antworten:

179

Kopieren Sie einfach mehrere Dateien auf einmal von der Kommandozeile

Es gibt verschiedene Möglichkeiten, wie Sie dies erreichen können. Das Einfachste, was ich gesehen habe, ist das Folgende.

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

Die Syntax verwendet den Befehl cp, gefolgt vom Pfad zu dem Verzeichnis, in dem sich die gewünschten Dateien befinden. Alle Dateien, die Sie kopieren möchten, sind in Klammern und durch Kommas getrennt.

Stellen Sie sicher, dass zwischen den Dateien keine Leerzeichen sind. Der letzte Teil des Befehls /home/usr/destination/ist das Verzeichnis, in das Sie die Dateien kopieren möchten.

oder wenn alle Dateien dasselbe Präfix, aber unterschiedliche Endungen haben, können Sie so etwas tun:

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

Wobei Datei1, Datei2, Datei3 und Datei4 kopiert würden.

Wie Sie die Frage formuliert haben, ist Ihrer Meinung nach genau das, wonach Sie suchen. Es hört sich jedoch auch so an, als ob Sie nach einem Befehl suchen, mit dem Sie aus einer Liste von Dateien lesen und alle in ein bestimmtes Verzeichnis kopieren können. Wenn dies der Fall ist, lassen Sie es mich wissen und ich bearbeite meine Antwort.

Umgang mit Duplikaten mit Python

Also habe ich ein kleines Python-Skript geschrieben, von dem ich glaube, dass es die Arbeit erledigen sollte. Ich bin mir jedoch nicht sicher, wie gut Sie sich mit Python auskennen (wenn überhaupt), daher werde ich versuchen, die Verwendung dieses Skripts so gut wie möglich zu erläutern, und bitte Sie, so viele Fragen wie nötig zu stellen.

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

Dieses Skript sollte relativ einfach zu bedienen sein. Kopieren Sie zunächst den obigen Code in das Programm gedit (sollte in Ubuntu vorinstalliert sein) oder in einen anderen Texteditor.

Nachdem dies abgeschlossen ist, speichern Sie die Datei als move.py in Ihrem Home-Verzeichnis (es kann sich um ein beliebiges Verzeichnis handeln, zur Vereinfachung der Anweisungen können Sie jedoch einfach das Home-Verzeichnis verwenden) oder fügen Sie das Verzeichnis, in dem sich die Datei befindet, zu Ihrem PATH hinzu. Dann cdzu Ihrem Home - Verzeichnis (oder was auch immer Verzeichnis gespeichert Sie move.py in) vom Terminal und geben Sie den folgenden Befehl ein :

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

Dies sollte alle Dateien, die im Quellverzeichnis aufgelistet sind, in das Zielverzeichnis kopieren, wobei Duplikate im Format pic (1) .jpg, pic (2) .jpg usw. vorliegen. file.txt sollte eine Datei sein, die alle Bilder auflistet, die Sie mit jedem Eintrag in einer eigenen separaten Zeile kopieren möchten.

Dieses Skript sollte sich in keiner Weise auf das Quellverzeichnis auswirken. Achten Sie jedoch darauf, die richtigen Pfade zum Quell- und Zielverzeichnis einzugeben. Das Schlimmste, was passieren kann, ist, dass Sie die Dateien in das falsche Verzeichnis kopieren.

Anmerkungen

  • In diesem Skript wird davon ausgegangen, dass sich alle Originalbilder im selben Verzeichnis befinden. Wenn Sie möchten, dass es auch Unterverzeichnisse überprüft, muss das Skript geändert werden.
  • Wenn Sie versehentlich einen Dateinamen falsch eingeben, gibt das Skript den Fehler
    "Datei existiert nicht" aus und fordert Sie auf, die Eingabetaste zu drücken, um fortzufahren, und das Skript kopiert den Rest der Liste weiter.
  • Vergessen Sie nicht, /sowohl den Pfad zum Quellverzeichnis
    als auch den Pfad zum Zielverzeichnis anzuhängen. Andernfalls gibt das Skript einen Fehler an Sie zurück.
Bryan
quelle
Vielen Dank, das hat den größten Teil meines Problems gelöst. Einige Dateien werden jedoch mindestens zweimal in der Liste angezeigt. Wie kann ich dafür sorgen, dass diese Duplikate automatisch umbenannt werden? (Ja, ich brauche die Duplikate für das, was ich tue.)
Jemand mit viel zu vielen Bildern
Sind die Duplikate aus verschiedenen Unterordnern oder sind die mit so etwas wie file.jpg und file (1) .jpg beschriftet? ansonsten bin ich mir nicht sicher wie du dateien hast die identisch sind. Um Ihre Frage ein wenig zu beantworten, ich glaube nicht, dass Sie in der Lage sein werden, einen einfachen Onliner zu finden, der Duplikate automatisch für Sie umbenennt. Ich denke, ein Bash oder eine andere Art von Skript müsste geschrieben werden, um diese Art von Funktionalität zu erhalten. Ich habe jedoch einige ziemlich lächerliche einzeilige Befehle gesehen, so dass vielleicht ein Linux-Assistent auftaucht und die Antwort liefert.
Bryan
Ich habe ursprünglich nur eine von jeder Datei, aber die Namen der Dateien sind zweimal oder öfter in der Liste. Mehr oder weniger, was ich tun muss, wenn ich versuche, eine Datei in den neuen Ordner zu legen, und eine Datei mit diesem Namen existiert bereits, muss ich eine (2) oder so an das Ende des Dateinamens anfügen und platziere es.
Jemand mit viel zu vielen Bildern
Ich möchte nur vorschlagen, den Teil zu betonen, in dem die Liste der zu kopierenden Dateien keine Leerzeichen enthält. Wenn es Leerzeichen gibt, auch zwischen den Dateien {foo, bar, ..}, funktioniert der Befehl nicht.
franksands
Für diejenigen, die nach weiteren Verknüpfungen suchen, können Sie die Befehlsersetzung verwenden, um für den absoluten Pfad der Dateien zu stehen, dh cp $(pwd)/{file1,file2} /path/to/dst/oder cp $(pwd)/{file1,file2} $(pwd)/{renamed1,renamed2}usw.
baelx
49

Vielleicht fehlt mir ein Detail Ihrer Frage, aber die Antworten scheinen übertrieben. Wenn Sie eine Befehlszeilenlösung und kein Skript wünschen, warum nicht:

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

Das Schöne dabei ist, dass Sie die Dateinamen mit einem Tab vervollständigen können

Ross Allen
quelle
5
Dies gibt eine "illegale Option --t" in macOS Sierra
geoyws
Gute Antwort, viel einfacher. @geoyws Vielleicht ist es eine POSIX- oder GNU-Sache, die Apples Version nicht hat. Es funktioniert gut für mich unter Debian Linux oder Windows mit MSYS2.
Underscore_d
netter vorschlag! arbeitete in Arch Linux.
Edu Ruiz
brew install coreutilsdann kannst du übliche gnu sachen mit gpräfix bekommen. Also das wirdgcp -t ....
T.Chmelevskij
Mac OS verwendet die BSD-Version von cp, und insbesondere haben weder OpenBSD noch FreeBSD diese Option, also ja - dies ist GNU- cp spezifisch. Es ist auch nicht durch den POSIX- Standard spezifiziert . Da dies eine Ubuntu-spezifische Site ist, ist dies akzeptabel, aber für die Portierung von Skripten zwischen Betriebssystemen ist es besser, den POSIX-Standard zu verwenden
Sergiy Kolodyazhnyy
7

Hier ist eine reine Bash-Lösung. Es liest Dateinamen aus einer Eingabedatei (einen pro Zeile) und kopiert jeden von ihnen, wobei Duplikate umbenannt werden.

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

Speichern Sie dieses Skript in einem Ordner in Ihrem $PATHund rufen Sie es mit der Liste der Pfade als Eingabe auf:

auto_copy.sh < file_paths.txt

Sie können das Ganze auch als Befehl vom Terminal aus ausführen:

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
quelle
1

Nach der Beschreibung der Frage ist mein Verständnis, dass:

  • Es gibt eine Liste von Dateien, vermutlich eine Textdatei input.txt
  • Die Liste enthält nur Dateinamen
  • Es gibt ein bestimmtes Verzeichnis, in dem sich diese Dateinamen befinden.

Somit kann man folgenden Befehl verwenden:

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

Erläuterung:

  • -I % Gibt das Symbol für die aktuell verarbeitete Datei an, die im Befehl verwendet werden soll
  • --arg-file=input.txt Gibt an, dass Argumente zum Befehlen verwendet werden sollen input.txt
  • cp /path/to/origin_dir/% /path/to/destination/führt den cpBefehl aus, wobei /path/to/origin_dir/%er durch /path/to/origin_dir/und den Namen der aktuell verarbeiteten Datei ersetzt wird.

Praktisches Beispiel:

$ 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
quelle