Sao chép nhiều tệp cụ thể từ thư mục này sang thư mục khác


133

Tôi có một thư mục hình ảnh lớn (hàng ngàn) và tôi có một danh sách dài các tệp, theo tên tệp chính xác, mà tôi cần sao chép sang thư mục khác. Tôi muốn biết liệu có cách nào để tôi có thể chọn một số tệp cụ thể từ thư mục này, theo tên và sao chép chúng sang thư mục khác, sử dụng thiết bị đầu cuối, mà không sao chép chúng riêng lẻ không?


Fyi, để sao chép các thư mục cụ thể sử dụng : cp -rp /copying/from/{folder1/,folder2/,folder3/} path/to/folder, nơi pđể sao chép quyền thư mục.
Raktim Biswas

Câu trả lời:


179

Chỉ cần sao chép nhiều tệp cùng một lúc từ dòng lệnh

Có một số cách bạn có thể đạt được điều này. Đơn giản nhất tôi đã thấy là sử dụng sau đây.

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

Cú pháp sử dụng lệnh cp theo sau là đường dẫn đến thư mục các tệp mong muốn được đặt trong tất cả các tệp bạn muốn sao chép được đóng gói trong ngoặc và phân tách bằng dấu phẩy.

Đảm bảo lưu ý rằng không có khoảng cách giữa các tệp. Phần cuối cùng của lệnh, /home/usr/destination/là thư mục bạn muốn sao chép các tệp vào.

hoặc nếu tất cả các tệp có cùng một tiền tố nhưng các kết thúc khác nhau, bạn có thể làm một cái gì đó như thế này:

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

Trong đó file1, file2, file3 và file4 sẽ được sao chép.

Từ cách bạn diễn đạt câu hỏi, tôi tin rằng đây là những gì bạn đang tìm kiếm nhưng cũng có vẻ như bạn đang tìm kiếm một lệnh để đọc từ danh sách các tệp và sao chép tất cả chúng vào một thư mục nhất định. Nếu đó là trường hợp cho tôi biết và tôi sẽ chỉnh sửa câu trả lời của tôi.

Xử lý trùng lặp với trăn

Vì vậy, tôi đã viết một kịch bản python nhỏ mà tôi tin rằng nên hoàn thành công việc. Tuy nhiên, tôi không chắc bạn thành thạo python như thế nào (nếu thông thạo tất cả) vì vậy tôi sẽ cố gắng giải thích cách sử dụng kịch bản này tốt nhất có thể và xin hỏi bao nhiêu câu hỏi về nó khi bạn cần.

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

Kịch bản này nên tương đối đơn giản để sử dụng. Trước hết, sao chép mã trên vào chương trình gedit (nên được cài đặt sẵn trong Ubuntu) hoặc bất kỳ trình soạn thảo văn bản nào khác.

Sau khi hoàn tất, hãy lưu tệp dưới dạng move.txt trong thư mục chính của bạn (nó có thể là bất kỳ thư mục nào nhưng để dễ hướng dẫn, chỉ cần sử dụng thư mục chính) hoặc thêm thư mục mà tệp được chứa trong PATH của bạn. Sau đó, cdvào thư mục chính của bạn (hoặc bất kỳ thư mục nào bạn đã lưu move.txt trong) từ thiết bị đầu cuối và nhập lệnh sau:

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

Điều này sẽ sao chép tất cả các tệp được liệt kê từ thư mục nguồn vào thư mục đích với các bản sao lấy định dạng pic (1) .jpg, pic (2) .jpg, v.v. file.txt phải là một tệp liệt kê tất cả các hình ảnh bạn muốn sao chép với mỗi mục trên dòng riêng biệt của nó.

Không có cách nào tập lệnh này ảnh hưởng đến thư mục nguồn, tuy nhiên chỉ cần đảm bảo nhập đúng đường dẫn đến thư mục nguồn và đích và điều tồi tệ nhất có thể xảy ra là bạn sao chép các tệp vào thư mục sai.

Ghi chú

  • Kịch bản này giả định rằng tất cả các hình ảnh gốc nằm trong cùng một thư mục. Nếu bạn muốn nó kiểm tra các thư mục con, kịch bản sẽ cần phải được sửa đổi.
  • Nếu bạn vô tình gõ nhầm tên tệp, tập lệnh sẽ phát ra lỗi
    "tập tin không tồn tại" và nhắc bạn "nhấn enter" để tiếp tục và tập lệnh sẽ tiếp tục sao chép phần còn lại của danh sách.
  • Đừng quên dấu vết /trên cả đường dẫn đến
    thư mục nguồn và đường dẫn đến thư mục đích. Nếu không, kịch bản sẽ nhổ một lỗi về bạn.

Cảm ơn bạn, điều đó đã giải quyết hầu hết vấn đề của tôi, tuy nhiên, một số tệp xuất hiện trong danh sách hai lần trở lên, Làm cách nào tôi có thể tự động đổi tên các bản sao này? (Vâng, tôi cần các bản sao cho những gì tôi đang làm.)
Một người có quá nhiều hình ảnh

Là các bản sao từ các thư mục phụ khác nhau hoặc được dán nhãn gì đó như file.jpg và tệp (1) .jpg? mặt khác, tôi không chắc làm thế nào bạn có các tập tin giống hệt nhau. Để phần nào trả lời câu hỏi của bạn, tôi không tin rằng bạn sẽ có thể tìm thấy một đơn giản trên lớp lót sẽ tự động đổi tên các bản sao cho bạn. Tôi nghĩ rằng một bash hoặc một số loại kịch bản khác sẽ phải được viết để có được loại chức năng đó. Tuy nhiên, tôi đã thấy một số lệnh một dòng khá lố bịch nên có thể một số trình hướng dẫn linux có thể hiển thị và cung cấp câu trả lời.
Bryan

Tôi chỉ có một trong mỗi tệp ban đầu, tuy nhiên tên của các tệp nằm trong danh sách hai lần trở lên. Nhiều hơn hoặc ít hơn những gì tôi cần cho nó để làm, khi cố gắng đặt một tệp vào thư mục mới và một tệp có tên đó đã tồn tại, tôi cần cho nó thêm (2) hoặc hơn vào cuối tên tệp và đặt nó.
Một người có quá nhiều hình ảnh

Tôi chỉ muốn đề nghị nhấn mạnh phần về việc không có khoảng trắng trong danh sách các tệp cần sao chép. Nếu có bất kỳ khoảng trắng nào, ngay cả giữa các tệp {foo, bar, ..}, lệnh sẽ không hoạt động.
franksands

Đối với những người tìm kiếm các phím tắt khác, bạn có thể sử dụng thay thế lệnh để thay thế cho đường dẫn tuyệt đối của các tệp, tức là cp $(pwd)/{file1,file2} /path/to/dst/hoặc cp $(pwd)/{file1,file2} $(pwd)/{renamed1,renamed2}, v.v.
baelx

49

Có lẽ tôi đang thiếu một chi tiết câu hỏi của bạn, nhưng câu trả lời có vẻ quá mức. Nếu bạn muốn một giải pháp dòng lệnh và không phải là một tập lệnh, tại sao không:

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

Điều tuyệt vời khi làm theo cách này là bạn có thể tab hoàn thành tên tệp


5
Điều này trả về một "tùy chọn bất hợp pháp --t" trong macOS Sierra
geoyws

Câu trả lời tuyệt vời, đơn giản hơn nhiều. @geoyws Có lẽ đó là thứ POSIX hoặc GNU mà phiên bản của Apple không có. Nó hoạt động tốt với tôi trên Debian Linux hoặc Windows với MSYS2.
gạch dưới

đề nghị tốt đẹp! làm việc trong arch linux.
Edu Ruiz

brew install coreutilssau đó bạn có thể nhận được các công cụ gnu thông thường với gtiền tố. Vì vậy, đó sẽ làgcp -t ....
T.Chmelevskij

Mac OS sử dụng phiên bản BSD cpvà đặc biệt là cả OpenBSDFreeBSD đều không có tùy chọn đó, vì vậy, có - đây là cp đặc thù của GNU . Nó cũng không được chỉ định bởi tiêu chuẩn POSIX . Vì đây là trang web cụ thể của Ubuntu, điều này có thể chấp nhận được, nhưng để chuyển các tập lệnh giữa các hệ điều hành, tốt hơn hết bạn nên tuân theo tiêu chuẩn POSIX
Sergiy Kolodyazhnyy

7

Đây là một giải pháp bash tinh khiết. Nó sẽ đọc tên tệp từ một tệp đầu vào (một dòng trên mỗi dòng) và sao chép từng tệp, đổi tên các bản sao.

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

Lưu tập lệnh này trong một thư mục trong của bạn $PATHvà gọi nó với danh sách các đường dẫn làm đầu vào:

auto_copy.sh < file_paths.txt

Bạn cũng có thể chạy toàn bộ điều dưới dạng một lệnh từ thiết bị đầu cuối:

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

Theo mô tả của câu hỏi, sự hiểu biết của tôi là:

  • có một danh sách các tập tin, có lẽ là một tập tin văn bản input.txt
  • danh sách chỉ chứa tên tệp
  • có một thư mục cụ thể nơi đặt các tên tệp này.

Vì vậy, người ta có thể sử dụng lệnh sau:

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

Giải trình:

  • -I % chỉ định biểu tượng cho tệp hiện đang được xử lý sẽ được sử dụng trong lệnh
  • --arg-file=input.txt chỉ định lấy các đối số để ra lệnh từ input.txt
  • cp /path/to/origin_dir/% /path/to/destination/sẽ thực hiện cplệnh với /path/to/origin_dir/%việc được thay thế bằng /path/to/origin_dir/và tên của tệp hiện đang được xử lý.

Ví dụ thực tế:

$ 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.