Vraag Meerdere specifieke bestanden kopiëren van de ene map naar de andere


Ik heb een grote map met afbeeldingen (duizenden) en ik heb een lange lijst met bestanden, op exacte bestandsnaam, die ik naar een andere map moet kopiëren. Ik wil weten of er een manier is om meerdere specifieke bestanden uit deze map op naam te selecteren en naar een andere map te kopiëren via de terminal, zonder ze afzonderlijk te kopiëren?


97
2017-08-01 05:44


oorsprong




antwoorden:


Kopieer eenvoudig meerdere bestanden tegelijk vanaf de opdrachtregel

Er zijn verschillende manieren om dit te bereiken. Het gemakkelijkste dat ik heb gezien, is om het volgende te gebruiken.

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

De syntaxis gebruikt de cp-opdracht gevolgd door het pad naar de map waarin de gewenste bestanden zich bevinden, met alle bestanden die u wilt kopiëren gewikkeld tussen haakjes en gescheiden door komma's.

Let op dat er geen spaties tussen de bestanden staan. Het laatste deel van het commando, /home/usr/destination/, is de map waarnaar u de bestanden wilt kopiëren.

of als alle bestanden hetzelfde prefix hebben maar verschillende eindes, zou je zoiets als dit kunnen doen:

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

Waar bestand1, bestand2, bestand3 en bestand4 worden gekopieerd.

Van hoe je de vraag formuleerde, ik geloof dat dit is waarnaar je op zoek bent, maar het klinkt ook alsof je misschien op zoek bent naar een commando om uit een lijst met bestanden te lezen en ze allemaal naar een bepaalde map te kopiëren. Als dat het geval is, laat het me weten en ik zal mijn antwoord bewerken.

Omgaan met duplicaten met python

Dus schreef ik een klein pythonscript waarvan ik geloof dat het de klus zou klaren. Ik weet echter niet zeker hoe goed je bent in python (als je al vertrouwd bent), dus ik zal proberen uit te leggen hoe je dit script zo goed mogelijk kunt gebruiken en vraag er zoveel mogelijk vragen over als je nodig hebt.

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

Dit script moet relatief eenvoudig te gebruiken zijn. Kopieer eerst de bovenstaande code naar het programma gedit (moet vooraf geïnstalleerd zijn in Ubuntu) of een andere teksteditor.

Nadat dit is voltooid, slaat u het bestand op als move.py in je homedirectory (het kan elke directory zijn, maar voor het gemak van de instructie kun je gewoon de homedirectory gebruiken) of de map toevoegen waarin het bestand zich bevindt in je PATH. Dan cd naar uw thuismap (of naar welke map u ook hebt bewogen) in de terminal en typ de volgende opdracht:

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

Dit zou alle bestanden die in de bronmap staan ​​moeten kopiëren naar de doelmap met duplicaten die de opmaak pic (1) .jpg, pic (2) .jpg enzovoort hebben. file.txt moet een bestand zijn met alle afbeeldingen die u wilt kopiëren met elk item op een aparte regel.

Dit script mag in geen geval de bronmap beïnvloeden, maar zorg er wel voor dat u de juiste paden naar de bron- en doelmap invoert en het ergste dat kan gebeuren is dat u de bestanden naar de verkeerde map kopieert.

Notes

  • In dit script wordt ervan uitgegaan dat alle originele afbeeldingen hetzelfde zijn directory. Als u wilt dat het submappen ook het script controleert moet worden aangepast.
  • Als u per ongeluk een bestandsnaam verkeerd typt, spuugt het script de fout uit
    "bestand bestaat niet" en vraagt ​​u om "druk op enter" om door te gaan en het script zal doorgaan met het kopiëren van de rest van de lijst.
  • Vergeet het achterblijven niet / op zowel het pad naar de bron
    map en pad naar de doelmap. Anders het script zal een fout terug naar je spuwen.

132
2017-08-01 06:04



Bedankt, dat loste het grootste deel van mijn probleem op, maar sommige bestanden verschijnen tweemaal of vaker in de lijst. Hoe kan ik ervoor zorgen dat deze dubbele namen automatisch worden hernoemd? (Ja, ik heb de duplicaten nodig voor wat ik aan het doen ben.) - Someone with far too many pict
Zijn de duplicaten uit verschillende submappen of zijn de labels iets als file.jpg en bestand (1) .jpg? anders weet ik niet zeker hoe je bestanden hebt die identiek zijn. Om je vraag enigszins te beantwoorden, geloof ik niet dat je een eenvoudige liner kunt vinden die automatisch duplicaten voor jou zal hernoemen. Ik denk dat een bash of een ander type script zou moeten worden geschreven om dat type functionaliteit te krijgen. Ik heb echter een aantal behoorlijk belachelijke eenregelopdrachten gezien, dus misschien kan een linux-wizard verschijnen en het antwoord geven. - Bryan
Ik heb oorspronkelijk maar één bestand van elk bestand, maar de namen van de bestanden staan ​​twee of meer keer in de lijst. Min of meer wat ik nodig heb om te doen, wanneer ik probeer een bestand in de nieuwe map te plaatsen, en een bestand met die naam bestaat al, ik moet er een (2) of zo aan toevoegen aan het einde van de bestandsnaam en plaats het. - Someone with far too many pict


Misschien mis ik een detail van uw vraag, maar de gegeven antwoorden lijken overdreven. Als u een opdrachtregeloplossing wilt en geen script, waarom niet:

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

Het leuke aan het op deze manier doen is dat je de bestandsnamen op tab kunt invullen


26
2017-08-25 17:48



Dit retourneert een "illegale optie - t" in macOS Sierra - geoyws
Geweldig antwoord, veel eenvoudiger. @geoyws Misschien is het een POSIX- of GNU-ding dat Apple's versie niet heeft. Het werkt goed voor mij op Debian Linux of Windows met MSYS2. - underscore_d
leuke suggestie! werkte in arch linux. - Edu Ruiz
brew install coreutils dan kun je gewoon GNU-dingen mee doen g voorvoegsel. Dat zal zo zijn gcp -t .... - T.Chmelevskij
Mac OS gebruikt BSD-versie van cp, en met name geen van beide OpenBSD noch FreeBSD heb die optie, dus ja - dit is GNU cp  specifiek. Het is ook niet gespecificeerd door POSIX standaard. Aangezien dit een Ubuntu-specifieke site is, is dit acceptabel, maar voor porting-scripts tussen OS's is het beter om vast te houden aan de POSIX-standaard - Sergiy Kolodyazhnyy


Hier is een pure bash-oplossing. Het leest bestandsnamen uit een invoerbestand (één per regel) en kopieert elk ervan, waarbij dubbele namen worden hernoemd.

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

Sla dit script op in een map in uw $PATH en noem het met de lijst met paden als invoer:

auto_copy.sh < file_paths.txt

Je kunt het hele ding ook uitvoeren als een commando van de 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;

6
2017-08-01 15:24





Volgens de beschrijving van de vraag is mijn inzicht dat:

  • er is een lijst met bestanden, vermoedelijk een tekstbestand input.txt
  • de lijst bevat alleen bestandsnamen
  • er is een bepaalde map waar deze bestandsnamen zich bevinden.

Zo kan men het volgende commando gebruiken:

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

Uitleg:

  • -I % geeft het symbool aan voor het momenteel verwerkte bestand dat in de opdracht moet worden gebruikt
  • --arg-file=input.txt specificeert om argumenten te nemen om van te bevelen input.txt
  • cp /path/to/origin_dir/% /path/to/destination/ zal optreden cp commando met /path/to/origin_dir/% wordt vervangen door /path/to/origin_dir/ en naam van het momenteel verwerkte bestand.

Praktisch voorbeeld:

$ 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

0
2018-05-26 07:32