Birden fazla belirli dosyayı bir klasörden diğerine kopyalama


133

Çok büyük bir resim klasörüm var (binlerce) ve başka bir klasöre kopyalamam gereken tam bir dosya adına göre uzun bir dosya listem var. Bu klasörden birkaç belirli dosyayı isimle seçip, ayrı ayrı kopyalamaksızın, terminali kullanarak başka bir klasöre kopyalamanın bir yolu olup olmadığını bilmek istiyorum.


Bilginize, kopyalama için özel klasörler kullanın: cp -rp /copying/from/{folder1/,folder2/,folder3/} path/to/foldernereye pklasör iznini kopyalama içindir.
Raktim Bis

Yanıtlar:


179

Birden fazla dosyayı aynı anda komut satırından kopyala

Bunu başarabilmenin birkaç yolu var. Gördüğüm en kolay aşağıdakileri kullanmak.

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

Sözdizimi, cp komutunu ve ardından dizine giden ve parantez içinde sarılmış ve virgüllerle ayrılmış, kopyalamak istediğiniz tüm dosyaların bulunduğu dizinin yolunu kullanır.

Dosyalar arasında boşluk olmadığına dikkat edin. Komutun son kısmı /home/usr/destination/, dosyaları kopyalamak istediğiniz dizindir.

veya tüm dosyalar aynı önek içeriyorsa ancak farklı sonlar varsa, bunun gibi bir şey yapabilirsiniz:

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

Burada dosya1, dosya2, dosya3 ve dosya4 kopyalanacak.

Soruyu nasıl ifade ettiğinize göre, aradığınız şeyin bu olduğuna inanıyorum, ancak bir dosya listesinden okumak ve hepsini belirli bir dizine kopyalamak için bir komut arıyor olabilirsiniz. Bu durumda, bana bildirin ve cevabımı düzenleyeyim.

Python ile kopyalarla uğraşmak

Bu yüzden işi bitirmesi gerektiğine inandığım küçük bir python senaryosu yazdım. Ancak, python'da ne kadar iyi tereddüt ettiğinizden emin değilim (eğer usta ise) bu betiği en iyi nasıl kullanabileceğimi açıklamaya çalışacağım ve lütfen bu konu hakkında istediğiniz kadar soru soracağım.

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

Bu betiğin kullanımı nispeten basit olmalıdır. Öncelikle, yukarıdaki kodu program gedit'e (Ubuntu'da önceden yüklenmiş olmalıdır) veya başka bir metin editörüne kopyalayın.

Bu işlem tamamlandıktan sonra dosyayı ev dizininize move.py olarak kaydedin (herhangi bir dizin olabilir ancak kullanım kolaylığı için sadece ev dizinini kullanmanıza izin verir) veya dosyanın PATH'inize bulunduğu dizini ekleyin. Ardından cdterminalden ana dizininize (ya da herhangi bir dizine taşınan dizine) ve aşağıdaki komutu yazın:

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

Bu, kaynak dizinden listelenen tüm dosyaları, pic (1) .jpg, pic (2) .jpg biçimini alarak kopyalanan hedef dizine kopyalamalıdır. file.txt , her giriş için kopyalamak istediğiniz tüm resimleri kendi ayrı satırlarında listeleyen bir dosya olmalıdır.

Bu komut dosyası kaynak dizini hiçbir şekilde etkilememelidir, ancak kaynak ve hedef dizine doğru yolları girdiğinizden emin olun ve olabilecek en kötüsü dosyaları yanlış dizine kopyalamanızdır.

notlar

  • Bu komut dosyası, orijinal resimlerin hepsinin aynı dizinde olduğunu varsayar. Alt dizinleri de kontrol etmesini istiyorsanız, komut dosyasının değiştirilmesi gerekecektir.
  • Yanlışlıkla bir dosya adını yanlış yazarsanız, komut dosyası
    "dosya yok" hatasını bildirir ve devam etmek için "enter" tuşuna basmanızı ister ve komut dosyası listenin geri kalanını kopyalamaya devam eder.
  • /Hem kaynak
    dizinin yolundaki hem de hedef dizinin yolundaki izlemeyi unutmayın . Aksi takdirde, komut dosyası size geri bir hata verecektir.

Sorunumun çoğunu çözdüğünüz için teşekkürler, ancak bazı dosyalar listede iki veya daha fazla görüntüleniyor. Bu kopyaları otomatik olarak nasıl yeniden adlandırabilirim? (Evet, yaptığım şey için kopyalara ihtiyacım var.)
Çok fazla resmi olmayan biri

Farklı alt klasörlerdeki kopyalar mı yoksa etiketli, file.jpg ve file (1) .jpg şeklinde etiketlenmiş mi? Aksi halde, özdeş dosyalarınız nasıl olduğundan emin değilim. Sorunuzu biraz cevaplamak için, sizin için yinelemeleri otomatik olarak yeniden adlandıracak basit bir liner bulabileceğinize inanmıyorum. Bence bir bash veya başka bir tür komut dosyası, bu tür bir işlevsellik elde etmek için yazılmalıdır. Ancak, bazı oldukça saçma bir satır komutları gördüm, bu yüzden belki bazı linux sihirbazı ortaya çıkıp cevap verebilir.
Bryan,

Başlangıçta her bir dosyadan yalnızca birine sahibim, ancak dosyaların adları listede iki ya da daha fazla. Yeni klasöre bir dosya yerleştirmeye çalışırken ve bu ada göre bir dosya zaten varsa, yapması gerekenler az ya da çok, dosya adının sonuna bir (2) vb. ve yerleştir.
Çok fazla olan biri,

Sadece kopyalanacak dosyalar listesinde boşluk kalmamasını vurgulamak istiyorum. Herhangi bir boşluk varsa, {foo, bar, ..} dosyaları arasında bile komut çalışmaz.
Franksands

Ayrıca kısayollar isteyenler için, dosyalar, yani mutlak yolu için durmak komut ikamesi yararlanabilecek cp $(pwd)/{file1,file2} /path/to/dst/ya cp $(pwd)/{file1,file2} $(pwd)/{renamed1,renamed2}, vb
baelx

49

Belki de sorunuzun bir detayını özlüyorum, ancak verilen cevaplar aşırı görünüyor. Bir komut satırı çözümü değil bir komut dosyası istiyorsanız, neden olmasın:

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

Bu şekilde yapmanın güzel yanı, dosya adlarını tamamlayabilmenizdir.


5
Bu, macOS Sierra'da "yasadışı bir seçenek --t" döndürür
geoyws

Harika cevap, çok basit. @geoyws Belki de Apple'ın sürümünde olmayan bir POSIX veya GNU şeydir. Benim için Debian Linux veya Windows'ta MSYS2 ile çalışıyor.
underscore_d

güzel öneri! arch linux'ta çalıştı.
Edu Ruiz

brew install coreutilso zaman gönek ile olağan gnu şeyler alabilirsiniz . Öyle olacakgcp -t ....
T.Chmelevskij

Mac OS BSD sürümünü kullanıyor cpve özellikle OpenBSD veya FreeBSD'nin bu seçeneği yok, bu yüzden evet - bu GNU'ya cp özgüdür. Ayrıca POSIX standardında belirtilmemiş . Bu Ubuntu'ya özgü bir site olduğundan, bu kabul edilebilir, ancak işletim sistemleri arasındaki komut dosyalarının taşınması için POSIX standardına
uymak

7

İşte saf bir bash çözümü. Bir giriş dosyasından (satır başına bir tane) dosya adlarını okuyacak ve kopyaları yeniden adlandırarak her birini kopyalayacaktır.

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

Bu betiği sizin içindeki bir klasöre kaydedin $PATHve giriş olarak yolların listesini kullanarak arayın:

auto_copy.sh < file_paths.txt

Ayrıca her şeyi terminalden komut olarak çalıştırabilirsiniz:

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

Sorunun açıklaması gereğince anladığım şudur:

  • bir dosya listesi, muhtemelen bir metin dosyası var input.txt
  • liste sadece dosya isimleri içeriyor
  • bu dosya adlarının bulunduğu belirli bir dizin var.

Böylece, aşağıdaki komutu kullanabilirsiniz:

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

Açıklama:

  • -I % komut içinde kullanılacak şu anda işlenen dosyanın sembolünü belirtir
  • --arg-file=input.txt komuttan argüman almayı belirtir input.txt
  • cp /path/to/origin_dir/% /path/to/destination/şu anda işlenen dosyanın adıyla değiştirilerek cpkomutu gerçekleştirir ./path/to/origin_dir/%/path/to/origin_dir/

Pratik örnek:

$ 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.