คัดลอกไฟล์เฉพาะหลายไฟล์จากโฟลเดอร์หนึ่งไปยังอีกโฟลเดอร์หนึ่ง


133

ฉันมีโฟลเดอร์รูปภาพจำนวนมาก (หลายพันรายการ) และฉันมีรายการไฟล์ที่ยาวโดยใช้ชื่อไฟล์ที่แน่นอนว่าฉันต้องคัดลอกไปยังโฟลเดอร์อื่น ฉันต้องการทราบว่ามีวิธีที่ฉันสามารถเลือกไฟล์เฉพาะหลายไฟล์จากโฟลเดอร์นี้โดยใช้ชื่อและคัดลอกไฟล์ไปยังโฟลเดอร์อื่นโดยใช้เทอร์มินัลโดยไม่ต้องคัดลอกทีละไฟล์หรือไม่?


Fyi สำหรับการคัดลอกโฟลเดอร์ที่เฉพาะเจาะจงใช้: cp -rp /copying/from/{folder1/,folder2/,folder3/} path/to/folder, ที่ไหนpมีไว้สำหรับคัดลอกสิทธิ์โฟลเดอร์
Raktim Biswas

คำตอบ:


179

เพียงคัดลอกหลายไฟล์พร้อมกันจากบรรทัดคำสั่ง

มีหลายวิธีที่คุณสามารถทำได้ วิธีที่ง่ายที่สุดที่ฉันเคยเห็นคือใช้สิ่งต่อไปนี้

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

ไวยากรณ์ใช้คำสั่ง cp ตามด้วยพา ธ ไปยังไดเร็กทอรีที่ไฟล์ที่ต้องการอยู่ในไฟล์ทั้งหมดที่คุณต้องการคัดลอกในวงเล็บและคั่นด้วยเครื่องหมายจุลภาค

ตรวจสอบให้แน่ใจว่าไม่มีช่องว่างระหว่างไฟล์ ส่วนสุดท้ายของคำสั่ง/home/usr/destination/คือไดเรกทอรีที่คุณต้องการคัดลอกไฟล์ลงใน

หรือถ้าไฟล์ทั้งหมดมีคำนำหน้าเหมือนกัน แต่ตอนจบแตกต่างกันคุณสามารถทำสิ่งนี้:

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

โดยที่ file1, file2, file3 และ file4 จะถูกคัดลอก

จากวิธีที่คุณพูดคำถามที่ฉันเชื่อว่านี่คือสิ่งที่คุณกำลังมองหา แต่ดูเหมือนว่าคุณอาจกำลังมองหาคำสั่งให้อ่านจากรายการของไฟล์และคัดลอกทั้งหมดไปยังไดเรกทอรีที่แน่นอน หากเป็นกรณีนี้ให้ฉันทราบและฉันจะแก้ไขคำตอบของฉัน

การจัดการกับรายการซ้ำด้วย python

ดังนั้นฉันจึงเขียนสคริปต์หลามเล็ก ๆ น้อย ๆ ที่ฉันเชื่อว่าควรจะทำงานให้เสร็จ อย่างไรก็ตามฉันไม่แน่ใจว่าคุณมีความรอบรู้ในงูหลาม (ถ้ารอบรู้เลย) ดังนั้นฉันจะพยายามอธิบายวิธีใช้สคริปต์นี้ให้ดีที่สุดเท่าที่จะทำได้และโปรดถามคำถามเกี่ยวกับเรื่องนี้ให้มากที่สุดเท่าที่คุณต้องการ

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

สคริปต์นี้ควรใช้ง่าย ก่อนอื่นให้คัดลอกโค้ดข้างต้นลงในโปรแกรม gedit (ควรติดตั้งไว้ล่วงหน้าใน Ubuntu) หรือโปรแกรมแก้ไขข้อความอื่น ๆ

หลังจากนั้นเสร็จแล้วให้บันทึกไฟล์เป็นmove.pyในโฮมไดเร็กตอรี่ของคุณ (อาจเป็นไดเรคทอรีใดก็ได้ แต่เพื่อความสะดวกในการเรียนการสอนให้ใช้แค่โฮมไดเร็กตอรี่ ) หรือเพิ่มไดเรกทอรีที่มีไฟล์อยู่ใน PATH ของคุณ จากนั้นcdไปที่โฮมไดเร็กตอรี่ของคุณ (หรือไดเรกทอรีใดก็ตามที่คุณบันทึก move.py ใน) จากเทอร์มินัลแล้วพิมพ์คำสั่งต่อไปนี้:

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

สิ่งนี้ควรคัดลอกไฟล์ทั้งหมดที่อยู่ในรายการจากไดเรกทอรีต้นทางไปยังไดเรกทอรีปลายทางโดยมีรายการซ้ำในรูปแบบ pic (1) .jpg, pic (2) .jpg และอื่น ๆ file.txtควรเป็นไฟล์ที่แสดงรายการรูปภาพทั้งหมดที่คุณต้องการคัดลอกด้วยแต่ละรายการในบรรทัดแยกต่างหาก

สคริปต์นี้จะไม่มีผลกับไดเรกทอรีต้นทาง แต่ควรตรวจสอบให้แน่ใจว่าได้ป้อนเส้นทางที่ถูกต้องไปยังไดเรกทอรีต้นทางและปลายทางและสิ่งที่แย่ที่สุดที่อาจเกิดขึ้นคือคุณคัดลอกไฟล์ไปยังไดเรกทอรีที่ไม่ถูกต้อง

หมายเหตุ

  • สคริปต์นี้อนุมานว่ารูปภาพต้นฉบับทั้งหมดอยู่ในไดเรกทอรีเดียวกัน หากคุณต้องการให้ตรวจสอบไดเรกทอรีย่อยเช่นกันสคริปต์จะต้องมีการแก้ไข
  • หากคุณพิมพ์ชื่อไฟล์ผิดพลาดสคริปต์จะคายข้อผิดพลาด
    "ไม่มีไฟล์" และแจ้งให้คุณ "กด Enter" เพื่อดำเนินการต่อและสคริปต์จะคัดลอกส่วนที่เหลือของรายการต่อไป
  • อย่าลืมการติดตาม/ทั้งเส้นทางไปยัง
    ไดเรกทอรีต้นทางและเส้นทางไปยังไดเรกทอรีปลายทาง มิฉะนั้นสคริปต์จะส่งข้อผิดพลาดกลับมาที่คุณ

ขอบคุณที่แก้ไขปัญหาส่วนใหญ่ของฉันได้อย่างไรบางไฟล์ปรากฏในรายการสองครั้งขึ้นไปฉันจะเปลี่ยนชื่อซ้ำเหล่านี้โดยอัตโนมัติได้อย่างไร (ใช่ฉันต้องการสำเนาที่ซ้ำกันสำหรับสิ่งที่ฉันทำ)
คนที่มีรูปมากเกินไป

ทำซ้ำจากโฟลเดอร์ย่อยที่แตกต่างกันหรือมีชื่อกำกับเช่น file.jpg และไฟล์ (1) .jpg หรือไม่ ไม่เช่นนั้นฉันไม่แน่ใจว่าคุณมีไฟล์ที่เหมือนกันอย่างไร เพื่อตอบคำถามของคุณฉันไม่เชื่อว่าคุณจะสามารถหาคำตอบง่ายๆได้ที่จะเปลี่ยนชื่อซ้ำให้คุณโดยอัตโนมัติ ฉันคิดว่าจะต้องมีการทุบตีหรือสคริปต์ชนิดอื่นเพื่อให้ได้ฟังก์ชันการทำงานประเภทนั้น อย่างไรก็ตามฉันได้เห็นคำสั่งหนึ่งบรรทัดที่น่าหัวเราะบางอย่างดังนั้นบางทีตัวช่วยสร้าง linux อาจปรากฏขึ้นและให้คำตอบ
ไบรอัน

ฉันมีเพียงหนึ่งในแต่ละไฟล์เริ่มแรก แต่ชื่อของไฟล์อยู่ในรายการสองครั้งขึ้นไป สิ่งที่ฉันต้องทำมากขึ้นหรือน้อยลงเมื่อพยายามวางไฟล์ในโฟลเดอร์ใหม่และไฟล์ที่มีชื่อนั้นมีอยู่แล้วฉันต้องการให้เพิ่ม (2) หรือต่อท้ายชื่อไฟล์ และวางไว้
คนที่มีรูปมากเกินไป

ฉันแค่ต้องการแนะนำให้เน้นส่วนที่เกี่ยวกับการไม่มีช่องว่างในรายการไฟล์ที่จะคัดลอก หากมีช่องว่างใด ๆ แม้ระหว่างไฟล์ {foo, bar, .. } คำสั่งจะไม่ทำงาน
franksands

สำหรับผู้ที่กำลังมองหาทางลัดเพิ่มเติมคุณสามารถใช้การทดแทนคำสั่งเพื่อเข้าสู่เส้นทางที่แน่นอนของไฟล์เช่นcp $(pwd)/{file1,file2} /path/to/dst/หรือcp $(pwd)/{file1,file2} $(pwd)/{renamed1,renamed2}อื่น ๆ
baelx

49

บางทีฉันอาจจะไม่มีรายละเอียดคำถามของคุณ แต่คำตอบที่ได้ดูเหมือนมากเกินไป หากคุณต้องการโซลูชันบรรทัดคำสั่งและไม่ใช่สคริปต์ทำไมไม่:

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

สิ่งที่ดีเกี่ยวกับการทำเช่นนี้คือคุณสามารถแท็บกรอกชื่อไฟล์


5
ส่งคืน "ตัวเลือกที่ผิดกฎหมาย --t" ใน macOS Sierra
geoyws

คำตอบที่ดีง่ายกว่ามาก @geoyws บางทีมันอาจเป็น POSIX หรือ GNU ที่เวอร์ชั่นของ Apple ไม่มี มันทำงานได้ดีสำหรับฉันบน Debian Linux หรือ Windows ด้วย MSYS2
underscore_d

คำแนะนำที่ดี! ทำงานใน arch linux
Edu Ruiz

brew install coreutilsจากนั้นคุณสามารถรับสิ่ง gnu ปกติด้วยgคำนำหน้า นั่นจะเป็นgcp -t ....
T.Chmelevskij

Mac OS ใช้รุ่น BSD cpและโดยเฉพาะOpenBSDและFreeBSDไม่มีตัวเลือกนั้นดังนั้นใช่ - นี่คือ GNU cp เฉพาะ มันไม่ได้ระบุโดยมาตรฐานPOSIX เนื่องจากนี่เป็นเว็บไซต์เฉพาะของ Ubuntu สิ่งนี้จึงเป็นที่ยอมรับ แต่สำหรับการย้ายสคริปต์ระหว่างระบบปฏิบัติการของ OS จะเป็นการดีกว่าที่จะใช้มาตรฐาน POSIX
Sergiy Kolodyazhnyy

7

นี่เป็นวิธีทุบตีบริสุทธิ์ มันจะอ่านชื่อไฟล์จากไฟล์อินพุต (หนึ่งรายการต่อบรรทัด) และคัดลอกแต่ละไฟล์โดยเปลี่ยนชื่อซ้ำ

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

บันทึกสคริปต์นี้ในโฟลเดอร์ในของคุณ$PATHและเรียกมันด้วยรายการเส้นทางเป็นอินพุต:

auto_copy.sh < file_paths.txt

คุณยังสามารถรันสิ่งทั้งหมดเป็นคำสั่งจากเทอร์มินัล:

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

ตามคำอธิบายของคำถามความเข้าใจของฉันคือ:

  • มีรายการไฟล์น่าจะเป็นไฟล์ข้อความ input.txt
  • รายการมีชื่อไฟล์เท่านั้น
  • มีไดเรกทอรีเฉพาะที่ชื่อไฟล์เหล่านี้ตั้งอยู่

ดังนั้นหนึ่งสามารถใช้คำสั่งต่อไปนี้:

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

คำอธิบาย:

  • -I % ระบุสัญลักษณ์สำหรับไฟล์ที่ถูกประมวลผลในปัจจุบันที่จะใช้ภายในคำสั่ง
  • --arg-file=input.txt ระบุว่าจะรับอาร์กิวเมนต์จากคำสั่ง input.txt
  • cp /path/to/origin_dir/% /path/to/destination/จะดำเนินการcpคำสั่งด้วย/path/to/origin_dir/%การถูกแทนที่ด้วย/path/to/origin_dir/และชื่อของไฟล์ที่ประมวลผลในปัจจุบัน

ตัวอย่างการปฏิบัติ:

$ 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.