Menyalin beberapa file spesifik dari satu folder ke folder lain

133

Saya memiliki folder besar gambar (ribuan), dan saya memiliki daftar panjang file, dengan nama file yang tepat, yang perlu saya salin ke folder lain. Saya ingin tahu apakah ada cara saya dapat memilih beberapa file spesifik dari folder ini, dengan nama, dan menyalinnya ke folder lain, menggunakan terminal, tanpa menyalinnya secara individual?

Seseorang dengan terlalu banyak foto
sumber
Fyi, untuk menyalin folder tertentu gunakan:, di cp -rp /copying/from/{folder1/,folder2/,folder3/} path/to/foldermana puntuk menyalin izin folder.
Raktim Biswas

Jawaban:

179

Cukup salin beberapa file sekaligus dari baris perintah

Ada beberapa cara Anda bisa mencapainya. Cara termudah yang saya lihat adalah menggunakan yang berikut ini.

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

Sintaks menggunakan perintah cp diikuti oleh path ke direktori file yang diinginkan terletak di dengan semua file yang ingin Anda salin dibungkus dengan tanda kurung dan dipisahkan dengan koma.

Pastikan untuk mencatat bahwa tidak ada spasi di antara file. Bagian terakhir dari perintah /home/usr/destination/,, adalah direktori tempat Anda ingin menyalin file.

atau jika semua file memiliki awalan yang sama tetapi ujung yang berbeda Anda bisa melakukan sesuatu seperti ini:

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

Di mana file1, file2, file3 dan file4 akan disalin.

Dari cara Anda mengucapkan pertanyaan, saya yakin inilah yang Anda cari, tetapi sepertinya Anda juga mencari perintah untuk membaca dari daftar file dan menyalinnya ke direktori tertentu. Jika demikian, beri tahu saya dan saya akan mengedit jawaban saya.

Berurusan dengan duplikat dengan python

Jadi saya menulis skrip python kecil yang saya percaya harus menyelesaikan pekerjaan. Namun, saya tidak yakin seberapa baik Anda berpengalaman dalam python (jika berpengalaman sama sekali) jadi saya akan mencoba menjelaskan cara menggunakan skrip ini sebaik mungkin dan tolong tanyakan sebanyak mungkin pertanyaan tentangnya sesuai kebutuhan.

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

Script ini harus relatif mudah digunakan. Pertama, salin kode di atas ke dalam program gedit (harus diinstal sebelumnya di Ubuntu) atau editor teks lainnya.

Setelah itu selesai, simpan file sebagai move.py di direktori home Anda (bisa berupa direktori apa saja tetapi untuk kemudahan pengajaran, cukup gunakan direktori home) atau tambahkan direktori file yang terkandung di dalam PATH Anda. Kemudian cdke direktori home Anda (atau direktori apa pun yang Anda simpan move.py) dari terminal dan ketikkan perintah berikut:

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

Ini harus menyalin semua file yang terdaftar dari direktori sumber ke direktori tujuan dengan duplikat mengambil format pic (1) .jpg, pic (2) .jpg dan sebagainya. file.txt harus berupa file yang mencantumkan semua gambar yang ingin Anda salin dengan setiap entri pada barisnya masing-masing.

Tidak mungkin skrip ini mempengaruhi direktori sumber, namun pastikan untuk memasukkan jalur yang benar ke direktori sumber dan tujuan dan yang terburuk yang bisa terjadi adalah Anda menyalin file ke direktori yang salah.

Catatan

  • Script ini mengasumsikan bahwa semua gambar asli berada di direktori yang sama. Jika Anda ingin memeriksa sub direktori juga skrip perlu dimodifikasi.
  • Jika Anda secara tidak sengaja salah ketik nama file, skrip akan memuntahkan kesalahan
    "file tidak ada" dan meminta Anda untuk "tekan enter" untuk melanjutkan dan skrip akan terus menyalin sisa daftar.
  • Jangan lupa /jejak di kedua jalur ke
    direktori sumber dan jalur ke direktori tujuan. Kalau tidak, skrip akan membalas kesalahan Anda.
Bryan
sumber
Terima kasih, yang telah menyelesaikan sebagian besar masalah saya, namun, beberapa file muncul dalam daftar dua kali atau lebih, Bagaimana saya dapat membuatnya otomatis mengganti nama duplikat ini? (Ya, saya perlu duplikat untuk apa yang saya lakukan.)
Seseorang dengan terlalu banyak gambar
Apakah duplikat dari sub folder yang berbeda atau diberi label sesuatu seperti file.jpg dan file (1) .jpg? kalau tidak, saya tidak yakin bagaimana Anda memiliki file yang identik. Untuk menjawab pertanyaan Anda, saya tidak yakin Anda akan dapat menemukan sederhana pada liner yang akan secara otomatis mengganti nama duplikat untuk Anda. Saya pikir bash atau beberapa jenis skrip lain harus ditulis untuk mendapatkan jenis fungsionalitas itu. Namun, saya telah melihat beberapa perintah satu baris yang cukup konyol sehingga mungkin beberapa wizard linux dapat muncul dan memberikan jawabannya.
Bryan
Saya hanya memiliki satu dari setiap file pada awalnya, namun nama-nama file ada dalam daftar dua kali atau lebih. Lebih atau kurang apa yang saya perlukan untuk melakukannya, ketika mencoba menempatkan file di folder baru, dan file dengan nama itu sudah ada, saya perlu untuk menambahkan (2) atau lebih ke akhir nama file dan letakkan.
Seseorang dengan terlalu banyak gambar
Saya hanya ingin menyarankan untuk menekankan bagian tentang tidak memiliki spasi dalam daftar file yang akan disalin. Jika ada spasi, bahkan di antara file {foo, bar, ..} perintah tidak akan berfungsi.
franksands
Bagi mereka yang mencari jalan pintas lebih lanjut, Anda dapat menggunakan substitusi perintah untuk berdiri di jalur absolut file, yaitu cp $(pwd)/{file1,file2} /path/to/dst/atau cp $(pwd)/{file1,file2} $(pwd)/{renamed1,renamed2}, dll.
baelx
49

Mungkin saya melewatkan detail pertanyaan Anda, tetapi jawaban yang diberikan tampak berlebihan. Jika Anda menginginkan solusi baris perintah dan bukan skrip, mengapa tidak:

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

Hal yang menyenangkan tentang melakukannya dengan cara ini adalah Anda dapat menabisi nama file dengan lengkap

Ross Allen
sumber
5
Ini mengembalikan "opsi ilegal - t" di macOS Sierra
geoyws
Jawaban yang bagus, jauh lebih sederhana. @geoyws Mungkin POSIX atau GNU yang tidak dimiliki versi Apple. Ini berfungsi baik untuk saya di Debian Linux atau Windows dengan MSYS2.
underscore_d
saran yang bagus! bekerja di linux lengkungan.
Edu Ruiz
brew install coreutilsmaka Anda bisa mendapatkan barang-barang gnu biasa dengan gawalan. Jadi itu akan menjadigcp -t ....
T.Chmelevskij
Mac OS menggunakan versi BSD cp, dan terutama OpenBSD atau FreeBSD tidak memiliki opsi itu, jadi ya - ini cp khusus untuk GNU . Itu juga tidak ditentukan oleh standar POSIX . Karena ini adalah situs spesifik Ubuntu, ini dapat diterima, tetapi untuk porting skrip antara OS lebih baik tetap menggunakan standar POSIX
Sergiy Kolodyazhnyy
7

Inilah solusi bash murni. Ini akan membaca nama file dari file input (satu per baris) dan menyalin masing-masing, mengganti nama duplikat.

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

Simpan skrip ini dalam folder di folder Anda $PATHdan beri nama lintasan sebagai input:

auto_copy.sh < file_paths.txt

Anda juga dapat menjalankan semuanya sebagai perintah dari 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
sumber
1

Sesuai deskripsi pertanyaan, pengertian saya adalah:

  • ada daftar file, mungkin file teks input.txt
  • daftar hanya berisi nama file
  • ada direktori tertentu di mana nama file ini berada.

Dengan demikian, seseorang dapat menggunakan perintah berikut:

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

Penjelasan:

  • -I % menentukan simbol untuk file yang sedang diproses untuk digunakan dalam perintah
  • --arg-file=input.txt menentukan untuk mengambil argumen dari perintah input.txt
  • cp /path/to/origin_dir/% /path/to/destination/akan melakukan cpperintah dengan /path/to/origin_dir/%diganti /path/to/origin_dir/dan nama file yang sedang diproses.

Contoh praktis:

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