Tại sao ký tự đại diện * khác nhau giữa các lệnh zip và rm?


58

Tôi tập hợp một tập lệnh để thực hiện một số thao tác tập tin cho tôi. Tôi đang sử dụng toán tử thẻ hoang dã *để áp dụng các chức năng cho tất cả các loại tệp, nhưng có một điều tôi không nhận được. Tôi có thể unziptất cả các tệp trong một thư mục như thế này

unzip "*".zip

Tuy nhiên, để xóa tất cả các tệp zip sau đó, tôi cần phải làm

rm *.zip

Đó là, nó không muốn các dấu ngoặc kép. Mặt khác, phần giải nén không hoạt động nếu tôi chỉ cho nó * (đưa ra cảnh báo rằng "các tệp không khớp").

Tại sao điều này lại khác? Đối với tôi, điều này có vẻ giống như hoạt động chính xác. Hay tôi đang sử dụng thẻ hoang dã không chính xác?

Giới thiệu về thẻ hoang dã trong Unix không thực sự đi sâu vào vấn đề này và tôi không thể tìm thấy bất cứ điều gì trong tài liệu rmhoặc ziptài liệu.

Tôi đang sử dụng thiết bị đầu cuối trên máy Mac (Yosemite).


4
Tôi không có ý tưởng unzipcó thể làm điều này mà không có for f in *.zip;do...donevòng lặp vỏ bình thường . Thật là một giao diện người dùng dòng lệnh không giống như unix.
Peter Cordes

@Peter Tôi nghĩ bạn hiểu nhầm tình hình. unzipáp dụng toàn cầu cho nội dung của một kho lưu trữ; bạn không thể lấy chúng từ bash bằng ký tự đại diện. (Bạn sẽ cần `` `cho f in unzip -l archive.zip; do ... xong`)
alexis

@alexis: Tôi biết về unzipviệc chấp nhận các khối lượng để khớp trong một tệp zip duy nhất. Nhưng điều này là khác nhau; Tôi thực sự đã thử unzip '*.zip'trong một thư mục có nhiều tệp zip và nó trích xuất tất cả các tệp từ tất cả các khóa. Như tôi đã nói, siêu kỳ lạ. tarkhông có bất kỳ chế độ hoạt động như thế.
Peter Cordes

1
@Peter Tôi thấy ... vâng thật kỳ lạ, đặc biệt là vì giải nén sẽ không chấp nhận nhiều đối số dòng lệnh! Rõ ràng là một thực hiện chỉ Windows. Tôi hiểu sai về mô tả nhiệm vụ của OP.
alexis

1
@alexis: PKZip trước ngày Windows . Đây là một chương trình dòng lệnh của DOS, được phát hành lần đầu tiên vào năm 1989. Cổng Unix sử dụng về cơ bản cùng một mã phân tích cú pháp cmdline, AFAIK.
Peter Cordes

Câu trả lời:


68

Bạn đã giải thích tình hình rất tốt. Phần cuối cùng của câu đố là unzipcó thể tự xử lý các ký tự đại diện:

http://www.info-zip.org/mans/unzip.html

TRANH LUẬN

tập tin [.zip]

...

Các biểu thức ký tự đại diện tương tự như các biểu thức được hỗ trợ trong các shell Unix thường được sử dụng (sh, ksh, csh) và có thể chứa:

* khớp với một chuỗi từ 0 ký tự trở lên

Bằng cách trích dẫn * ký tự đại diện, bạn đã ngăn vỏ của mình mở rộng nó, để unzipnhìn thấy ký tự đại diện và xử lý việc mở rộng nó theo logic riêng của nó.

rm, ngược lại, không tự mình hỗ trợ các ký tự đại diện , vì vậy cố gắng trích dẫn một ký tự đại diện sẽ hướng dẫn rmtìm kiếm một dấu hoa thị theo nghĩa đen trong tên tệp.

Lý do unzip *.zipkhông hoạt động là unzipcú pháp của đơn giản là không cho phép nhiều tệp zip; nếu có nhiều tham số, nó hy vọng các tham số thứ 2 và tiếp theo sẽ là các tệp trong kho lưu trữ:

giải nén [-Z] [-cflptTuvz [abjnoqsCDKLMUVWX $ /: ^]]


6
cảm ơn, điều đó có ý nghĩa Nếu tôi hiểu chính xác, trong một trường hợp tôi đang nói unzipngôn ngữ của chính mình, trong trường hợp khác là biệt ngữ chung không trộn?
patrick

6
Chính xác. Điều quan trọng là phải ghi nhớ những gì vỏ của bạn làm so với những gì một chương trình làm.
Jeff Schaller

7
pkzip có nguồn gốc trên DOS mà không mở rộng các ký tự đại diện được chuyển đến các chương trình.
Thorbjørn Ravn Andersen

11
@patrick cách unix xử lý nhiều tệp với một chương trình chỉ có thể hoạt động với một tệp tại một thời điểm là sử dụng một vòng lặp. ví dụ for f in *.zip ; do unzip -v "$f" ; done. và một phần lớn lý do TẠI SAO shell thực hiện việc mở rộng tên tệp, v.v. .
cas

25

Sự khác biệt giữa hai lệnh đó là *ký tự được trích dẫn . Nếu bạn gọi một lệnh trong shell và sử dụng *ký tự cho một đối số, chính shell đó sẽ đánh giá đối số. Xem ví dụ này:

$ ls
file1.zip  file2.zip  file3.zip  file4.txt

Bây giờ với một *:

$ ls *.zip
file1.zip  file2.zip  file3.zip

Shell đánh giá ký tự đại diện và xây dựng một lệnh như sau:

$ ls file1.zip  file2.zip  file3.zip

Với một ký tự đại diện được trích dẫn, nó được hiểu là một tệp có tên (theo nghĩa đen) *.zip:

$ ls "*".zip
ls: cannot access *.zip: No such file or directory

Các unziptiện ích không thể được gọi với nhiều file nén như các đối số. Nhưng, nhà phát triển đã chọn một cách khác cho việc này. Từ trang hướng dẫn:

tập tin [.zip]

[...] Các biểu thức ký tự đại diện tương tự như các biểu thức được hỗ trợ trong các shell Unix thường được sử dụng (sh, ksh, csh) [...] ( Đảm bảo trích dẫn bất kỳ ký tự nào có thể được hệ điều hành giải thích hoặc sửa đổi , đặc biệt là trong Unix và VMS.)


Bạn có biết tại sao các tác giả unzipchọn đi theo con đường đó, thay vì cho phép nhiều tệp nén dưới dạng đối số không?
David Etler

@DavidEtler Tôi cũng không biết.
hỗn loạn

1
Tôi không thể nói lý do tại sao, @DavidEtler, nhưng được xây dựng, giải nén cú pháp chấp nhận tên tệp sau khi tệp zip được coi là nội dung của tệp zip đó. Sẽ không rõ ràng cho dù bạn có ý định cho tệp zip thứ hai là tham số "giải nén cho tôi" hay "giải nén tệp zip nội bộ này khỏi tệp lưu trữ trước đó".
Jeff Schaller

@DavidEtler không biết các nhà phát triển đã nghĩ gì, nhưng mọi thứ trở nên chậm hơn và nhỏ hơn rất nhiều . Bạn thường không xử lý nhiều hơn một tệp zip cùng một lúc. Bạn đã có đĩa mềm chứa 90 hoặc 250kB và bạn thực sự hạnh phúc khi có ổ đĩa 10 MB. Mọi thứ đã được nén bởi vì chúng phải như vậy, không chỉ cho vận chuyển hệ thống giao nhau.
Joe

7

Sự khác biệt là trong trường hợp đầu tiên, vỏ tự mở rộng toàn cầu:

% cd /                                                       
% echo *
Applications Library Network System Users Volumes bin cores ...
% 

trong trường hợp thứ hai, chính ứng dụng Does Something ™ với ký tự nghĩa đen đó:

% cd /
% perl -E 'chdir "/tmp" or die; say for glob($ARGV[0])' "*"
com.apple.launchd.aj4FEhYqm5
...

Nếu không được trích dẫn, lớp vỏ đầu tiên sẽ mở rộng toàn cầu và lệnh sẽ được chạy với bất cứ thứ gì mà lớp vỏ mà toàn cầu mở rộng ra.


2

Một lệnh sẽ nhận được các đối số sau khi chúng được xử lý bởi shell.

Trong lần xử lý đầu tiên, phần không trích dẫn *sẽ được mở rộng bằng shell (vào danh sách các tệp trong thư mục hiện tại (pwd) khớp với mẫu):

echo *.zip

Sẽ liệt kê tất cả .zipcác tập tin. Nhưng echo "*".zip"sẽ không .

Trong lần xử lý đầu tiên, một trích dẫn "*"sẽ không được mở rộng, nó sẽ được trao cho lệnh giải nén dưới dạng tham số (sau khi trích dẫn đã bị xóa). Lệnh giải nén sẽ nhận được một tham số *.zip:

$ echo unzip "*".zip
unzip *.zip

Đó là lệnh giải nén mở rộng *danh sách các tập tin.


Điều thú vị là hai lệnh này sẽ không thực hiện chính xác cùng một hành động cuối cùng và ai sẽ mở rộng các *thay đổi:

unzip "*".zip                ### the command unzip expands `*.zip`.
unzip *.zip                  ### the shell expands `*.zip`.

Lệnh đầu tiên nhận được lệnh *.zipmở rộng để xử lý tất cả các tệp. Lệnh thứ hai unzipsẽ nhận được một danh sách tất cả .zipcác tệp trong pwd, nó sẽ không xử lý, vì nhà phát triển giải nén đã chọn từ chối mở rộng nhiều hơn một ziptệp.


0

Các trích dẫn là cần thiết vì cách zip xử lý nhiều đối số:

rm: xóa tất cả các tệp trong danh sách đối số

zip: giải nén tệp trong đối số đầu tiên. chỉ giải nén các tập tin trong các đối số còn lại.

$ ls *.zip
file1.zip  file2.zip  file3.zip
$ unzip *.zip
Archive:  file1.zip
caution: filename not matched:  file2.zip
caution: filename not matched:  file3.zip

như bạn có thể thấy, nó cố gắng tìm file2.zip và file3.zip bên trong file1.zip

để cho phép bạn trích xuất nhiều tệp zip cùng một lúc, zip hỗ trợ phiên dịch toàn cầu, với một kết quả khác.

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.