Чому символ подвійної картки * настільки різний між командами zip та rm?


58

Я склав сценарій, щоб зробити деякі файлові операції для мене. Я використовую оператор wild card, *щоб застосувати функції до всіх файлів типу, але я не отримую одного. Я можу unzipвсі файли в такій папці

unzip "*".zip

Однак, щоб потім видалити всі поштові файли, мені потрібно це зробити

rm *.zip

Тобто не хоче лапок. Зніміть розпакування, з іншого боку, не працює, якщо я просто даю його * (дає мені попередження про те, що "файли не збігалися").

Чому це різне? Мені це здається точно такою ж операцією. Або я неправильно використовую подвійну карту?

Вступ у підказку в Unix насправді не займається цим, і я не зміг знайти нічого в документі rmабо zipдокументах.

Я використовую термінал на Mac (Yosemite).


4
Я не уявляв, що unzipможна обійтися без нормальної for f in *.zip;do...doneпетлі оболонки. Такий дивний інтерфейс командного рядка, що не нагадує unix.
Пітер Кордес

@Peter Я думаю, ви неправильно розумієте ситуацію. unzipзастосовує глобус до вмісту архіву; ви не зможете дістати їх з башмаку з підстановкою. (Вам знадобиться `` для f in unzip -l archive.zip; do ... done ')
alexis

@alexis: Я знав про unzipприйняття глобусів у відповідність до одного поштового файлу. Але це інакше; Я насправді спробував unzip '*.zip'у каталозі з кількома поштовими файлами, і він витягує всі файли з усіх блискавок. Як я вже казав, супер дивно. tarне має такого режиму роботи.
Пітер Кордес

1
@ Peeter Я бачу ... так, це дивно, тим більше, що unzip не прийме декілька аргументів командного рядка! Ясна реалізація лише для Windows. Я неправильно інтерпретував опис завдання ОП.
alexis

1
@alexis: PKZip попередньо побачив Windows . Це програма командного рядка DOS, вперше випущена в 1989 році. Порт Unix використовує в основному той же код, що аналізує cmdline, AFAIK.
Пітер Кордес

Відповіді:


68

Ви дуже добре пояснили ситуацію. Завершальний фрагмент головоломки полягає в тому, що вона unzipможе сама поводитись з підказками:

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

АРГУМЕНТИ

файл [.zip]

...

Виразні вирази подібні до тих, що підтримуються у звичайних оболонках Unix (sh, ksh, csh) і можуть містити:

* відповідає послідовності з 0 або більше символів

Цитуючи * wildcard, ви запобігли розширенню вашої оболонки, щоб unzipпобачити підстановку та вирішити її розширення відповідно до власної логіки.

rmНа відміну від цього, не підтримує символи підключення самостійно , тому спроба цитувати підстановку дозволить rmшукати буквальну зірочку замість імені файлу.

Причина, unzip *.zipяка не працює, полягає в тому unzip, що синтаксис просто не дозволяє створювати кілька поштових файлів; якщо є кілька параметрів, він очікує, що другий та наступні будуть файлами в архіві:

unzip [-Z] [-cflptTuvz [abjnoqsCDKLMUVWX $ /: ^]] файл [.zip] [файл (и) ...] [-x xfile (s) ...] [-d exdir]


6
дякую, це має сенс! якщо я правильно розумію, в одному випадку я розмовляю unzipвласною мовою, а в іншому - загальним мовою unix?
Патрік

6
Правильно. Важливо пам’ятати, що робить ваша оболонка та що робить програма.
Джефф Шаллер

7
pkzip зародився на DOS, який не розширював макіяж, переданий програмам.
Thorbjørn Ravn Andersen

11
@patrick Унікальним способом обробки декількох файлів з програмою, яка може працювати лише з одним файлом одночасно, є використання циклу. напр for f in *.zip ; do unzip -v "$f" ; done. і велика частина причини, чому саме оболонка робить розширення імені файлів і т. д., це те, що кожній окремій програмі не доведеться (це призведе до того, що безліч самостійно написаних реалізацій розширення підстановки, які відрізнялися невеликими, але дратівливими способами) .
cas

25

Різниця між цими двома командами - це цитований *символ. Якщо ви викликаєте команду в оболонці і використовуєте *символ для аргументу, сама оболонка оцінить аргумент. Дивіться цей приклад:

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

Тепер із *:

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

Оболонка оцінює підстановку та будує команду наступним чином:

$ ls file1.zip  file2.zip  file3.zip

З цитованим підстановкою він інтерпретується як файл з назвою (буквально) *.zip:

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

unzipУтиліта не може бути викликаний декількома стислих файлів в якості аргументів. Але, розробник обрав для цього інший шлях. На сторінці сторінки:

файл [.zip]

[...] Виразні вирази подібні до тих, що підтримуються у часто використовуваних оболонках Unix (sh, ksh, csh) [...] ( Обов'язково вкажіть будь-який символ, який в іншому випадку може бути інтерпретований або модифікований операційною системою , особливо в Unix і VMS.)


Чи знаєте ви, чому автори unzipвирішили піти цим маршрутом, а не допускати для аргументів кілька файлів-блискавок?
Девід Етлер

@DavidEtler Я теж не знаю.
хаос

1
Я не можу сказати, чому і @DavidEtler, але вбудований синтаксис unzip приймає назви файлів після zipfile, які, як передбачається, містять цей zipfile. Було б неоднозначно, чи ви мали на увазі для другого zip-файлу параметр "розпакувати мене" або "розпакуйте цей внутрішній поштовий файл з попереднього архіву".
Джефф Шаллер

@DavidEtler не знає, про що думали розробники, але тоді все було набагато повільніше і менше. Зазвичай ви не мали справу з більш ніж одним поштовим файлом одночасно. У вас були дискети, які вміщали 90 або 250 КБ, і ви були дуже щасливі, що накопичувач на 10 МБ. Речі стискалися, бо вони мали бути, а не лише для міжсистемного транспорту.
Джо

7

Різниця полягає в тому, що в першому випадку сама оболонка розширює глобус:

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

тоді як у другому випадку сама програма робить щось з цим буквальним символом:

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

Якщо без котирування, оболонка спочатку розгортає глобус, і команда буде виконуватися з тим, на що розгорнувся цей глобус оболонки.


2

Команда отримає аргументи після того, як вони будуть оброблені оболонкою.

При першій обробці без котирування *буде розширено оболонку (до списку файлів у цьому каталозі (pwd), які відповідають шаблону):

echo *.zip

Буде список усіх .zipфайлів. Але неecho "*".zip" буде .

При першій обробці цитата "*"не розширюватиметься, вона буде віддана команді unzip як параметр (після видалення цитування). Команда unzip отримає параметр *.zip:

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

Розгорнути *до списку файлів можна команду unzip .


Цікаво також, що ці дві команди не будуть виконувати абсолютно однакову остаточну дію, і хто розширює *зміни:

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

Перша команда отримує, *.zipяку вона розширює для обробки всіх файлів. Друга команда unzipотримає список усіх .zipфайлів у pwd, який він не обробить, оскільки розпакувач розробник вирішив відхилити розширення більш ніж одного zipфайлу.


0

Цитати потрібні через те, як zip обробляє декілька аргументів:

rm: видаліть усі файли зі списку аргументів

zip: розпакуйте файл у першому аргументі. витягуйте лише файли з решти аргументів.

$ 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

як бачите, він намагається знайти file2.zip та file3.zip всередині file1.zip

щоб дозволити вам витягувати кілька поштових файлів одночасно, zip підтримує інтерпретацію глобуса самостійно, з іншим результатом.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.