Làm cách nào để sao chép nhiều tệp bằng ký tự đại diện?


42

Tôi có một thư mục chứa một số tệp trong đó ABC. * (Có khoảng 100 tệp như vậy). Tôi muốn sao chép tất cả chúng vào các tệp mới có tên bắt đầu bằng DEF. *

Vì vậy, tôi muốn

ABC.Page1
ABC.Page2
ABC.Topic12
...etc

sao chép vào

DEF.Page1
DEF.Page2
DEF.Topic12
...etc

Cách đơn giản nhất để làm điều này với lệnh batch (trong BASH hoặc tương tự) là gì? Tôi đang suy nghĩ điều gì đó liên quan đến sed hoặc awk hoặc xargs, nhưng tôi gặp khó khăn trong việc tìm ra cú pháp. Tôi có thể viết một tập lệnh Python, nhưng tôi nghĩ có lẽ có một giải pháp dòng lệnh không quá phức tạp.


Một mctrình quản lý tệp đáng kính có sự hỗ trợ rộng rãi nhất cho loại đổi tên hàng loạt này.
Oakad

@oakad tarcũng không phải là gà xuân. Xem câu trả lời của tôi cho một ví dụ.
mikeerv

Câu trả lời:


41

Làm thế nào về một cái gì đó như thế này trong bash:

for file in ABC.*; do cp "$file" "${file/ABC/DEF}";done

bạn có thể kiểm tra nó bằng cách đặt echo trước lệnh cp:

for file in ABC.*; do echo cp "$file" "${file/ABC/DEF}";done

hoàn hảo. thậm chí đơn giản hơn tôi tưởng tượng.
Bạch tuộc

Nó sẽ đủ tốt trong hầu hết các trường hợp nhưng kiểm tra tiếng vang là rất quan trọng ở đây. Không bao giờ làm điều này trong một kịch bản . Để biết thêm thông tin, hãy đọc những cạm bẫy bash
pawel7318

@ pawel7318, liên kết bạn đưa ra, trong khi lời khuyên tuyệt vời, dường như không áp dụng cho lệnh được đưa ra ở trên. Các trường hợp cạnh duy nhất tôi thấy với lệnh này là: (1) Không kiểm tra xem tệp đích đã tồn tại hay chưa nếu tệp đích đã tồn tại dưới dạng thư mục (sẽ sao chép tệp vào thư mục, giữ nguyên tên hiện tại của nó), và (2) nếu có quá nhiều tệp mà bản mở rộng toàn cầu không thể vừa với một dòng lệnh.
tự đại diện

1
Tôi nhận được điều này: cp /usr/local/lib/libboost* /usr/local/lib/libboost*với kiểm tra tiếng vang.
Tomáš Zato

8

Để thực hiện điều này một cách hiệu quả với số lượng lớn tệp, tốt hơn là tránh bắt đầu một cpquy trình khác nhau cho mỗi tệp . Một cách sẽ là sao chép sau đó đổi tên chúng bằng cách sử dụng prename( renameđược liên kết theo cách này theo mặc định trên các bản phát hành dựa trên Debian). Sử dụng cái này và Linux mktemp:

tmp=$(mktemp -d --tmpdir=.)
cp ABC.* "$tmp"
prename "s:$tmp/ABC:DEF:" "$tmp/"*
rmdir "$tmp"

Cập nhật

Trên thực tế paxcó thể là một cách tốt hơn để đi đến đây:

pax -rws '/^ABC/DEF/' ABC.* .

Thật không may, mặc dù paxlà cả POSIX và Linux Standard Base, một số distro hiện bao gồm nó theo mặc định.


cảm ứng đẹp bằng cách sử dụng: làm dấu phân cách để tránh thoát.
Clayton Stanley

5

tar sẽ làm điều này cho bạn thực sự nhanh chóng.

KIỂM TRA

Đầu tiên tôi tạo 2 thư mục và 10 tệp:

% mkdir test1 test2 ; cd test1
% for n in `seq 1 10` ; do touch ABC.file$n ; done
% ls

> ABC.file1   ABC.file2  ABC.file4  ABC.file6  ABC.file8
> ABC.file10  ABC.file3  ABC.file5  ABC.file7  ABC.file9

Sau đó, tôi đã sao chép chúng:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC/DEF/' -xf -
% ls ../test2

> DEF.file1   DEF.file2  DEF.file4  DEF.file6  DEF.file8
> DEF.file10  DEF.file3  DEF.file5  DEF.file7  DEF.file9

BIẾN ĐỔI

Vì vậy, GNU tarsẽ chấp nhận sed --transform=EXPRESSIONđổi tên tập tin. Điều này thậm chí có thể đổi tên chỉ một số các tập tin. Ví dụ:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC\(.*[0-5]\)/DEF\1/' -xf -
% ls ../test2

> ABC.file6  ABC.file8  DEF.file1   DEF.file2  DEF.file4
> ABC.file7  ABC.file9  DEF.file10  DEF.file3  DEF.file5

Vì vậy, đó là một lợi thế.

SUỐI

Cũng xem xét rằng đây chỉ là hai tarquy trình - và điều đó sẽ không thay đổi bất kể số lượng tệp của bạn.

tar | tar

tarđược tối ưu hóa như bạn có thể muốn nó được. Điều này sẽ không bao giờ có số lượng đối số vấn đề hoặc các tiến trình con chạy trốn. Đây chỉ là A> B được thực hiện.

LẬP LUẬN

Tôi sử dụng 7 đối số riêng biệt kết hợp giữa hai tarquá trình của tôi ở đây. Điều quan trọng nhất được liệt kê ở đây đầu tiên:

-stdout / stdin - điều này thông báo tarrằng nó sẽ truyền trực tiếp đầu vào hoặc đầu ra của nó đến hoặc từ stdin/stdoutđó nó sẽ diễn giải chính xác tùy thuộc vào việc nó có đang xây dựng hoặc trích xuất một kho lưu trữ hay không.

-ctạo - điều này nói tarđể xây dựng kho lưu trữ. Đối số tiếp theo tarmong đợi là ...

-ftệp - chúng tôi xác định rằng tarsẽ làm việc với một fileđối tượng chứ không phải là thiết bị băng hoặc bất cứ thứ gì. Và tập tin mà nó sẽ làm việc với, như đã lưu ý ở trên, là stdin/stdout- nói cách khác, của chúng tôi |pipe.

./*tất cả $ PWD / tệp - không quá nhiều để giải thích ở đây ngoại trừ đối số lưu trữ đến trước, vì vậy -sau đó ./*.

... và ở phía bên kia của |pipe...

-Cthay đổi thư mục - điều này thông báo tarrằng nó cần thay đổi thành thư mục tôi chỉ định trước khi thực hiện bất kỳ hành động nào khác, vì vậy nó có hiệu quả ngay cd ../test2trước khi giải nén.

--transform='s/ed/EXPR/'- như đã được đề cập, điều này đã đổi tên. Nhưng các tài liệu chỉ ra rằng nó có thể có bất kỳ sedbiểu thức hay //flag.

-xtrích xuất - sau khi tarthay đổi thư mục đích của chúng tôi và nhận được hướng dẫn đổi tên của chúng tôi, chúng tôi hướng dẫn nó bắt đầu trích xuất tất cả các tệp vào thư mục hiện tại của nó từ -f - |pipetệp lưu trữ. Không có bí ẩn.


1
Đây là paxgiải pháp cho câu hỏi này. Tôi sẽ thêm nó vào câu trả lời của mình, nhưng tôi nghĩ nó phù hợp hơn ở đây -pax -rws '/^ABC/DEF/' ABC.* .
Graeme

@Graeme - woah - cách đó tốt hơn! Man, nó cũng đánh bại địa ngục vì đổi tên ngọc trai! Bạn nên đặt câu hỏi này trong câu trả lời của mình - paxlà POSIX được chỉ định - do đó pax.
mikeerv

paxcó thể là POSIX, nhưng nó hiếm khi được cài đặt theo mặc định.
Graeme

4

Nếu bạn không phiền khi sử dụng một công cụ ít tiêu chuẩn hơn, tôi khuyên bạn nên sử dụng mmv (di chuyển hàng loạt) được viết cho loại nhiệm vụ này. Sử dụng mcp(bản sao hàng loạt), là một phần của bộ, bạn chỉ cần làm

mcp "ABC.*" "DEF.#1"

Chính xác thì không dễ tìm thấy các gói tải xuống. Gói Debian hiện tại (mà Arch cũng sử dụng trong AUR) để biên dịch tại nhà có thể tìm thấy ở đây .


cài đặt trên Ubuntu 15.10 ra khỏi hộp,apt-get install mmv
Thufir

2

Trong zsh, đặt các dòng sau vào .zshrc:

autoload -U zmv
alias zmv='noglob zmv'
alias zcp='zmv -C'
alias zln='zmv -L'

Sau đó, trên dòng lệnh, bạn có thể chạy

zcp 'ABC(.*)' 'DEF$1'

hoặc đơn giản

zcp -W ABC.* DEF.*

Trong một shell khác, miễn là bạn đã cài đặt zsh:

zsh -c 'autoload zmv; noglob zmv -CW ABC.* DEF.*'

1

Bạn có thể làm điều này:

for i in ABC.*; do cp {ABC,DEF}."${i#*.}"; done

Có thể có điều gì đó tôi không thấy, nhưng làm cách nào để đặt nhiều điểm đến? Tôi đang sử dụng vòng lặp for để lấy từng cái. Tôi đã kiểm tra mã trước đó và nó hoạt động như mong đợi, vì vậy tôi sẽ đánh giá cao lời giải thích của bạn.
Sara Fauzia

Đó là xấu của tôi, tôi đọc sai câu trả lời của bạn. :-)
Chris Down

Làm thế nào tôi nên đọc "${i#*.}"bit?
dumbledad

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.