Я составил скрипт для выполнения некоторых файловых операций для себя. Я использую оператор wild card, *
чтобы применять функции ко всем файлам определенного типа, но есть одна вещь, которую я не понимаю. Я могу unzip
все файлы в папке, как эта
unzip "*".zip
Однако, чтобы удалить все zip-файлы впоследствии, мне нужно сделать следующее:
rm *.zip
То есть, он не хочет кавычек. С другой стороны, распаковка не работает, если я просто укажу * (выдает предупреждение, что "файлы не были сопоставлены").
Почему это отличается? Мне кажется, что это та же самая операция. Или я неправильно использую wild card?
Знакомство с wild cardв Unix на самом деле не вникают в это, и я не смог найти ничего в rm
документации zip
.
Я использую терминал на Mac (Yosemite).
решение1
Вы очень хорошо объяснили ситуацию. Последний элемент головоломки — это то, что unzip
может обрабатывать подстановочные знаки самостоятельно:
http://www.info-zip.org/mans/unzip.html
АРГУМЕНТЫ
файл[.zip]
...
Подстановочные выражения аналогичны тем, которые поддерживаются в широко используемых оболочках Unix (sh, ksh, csh), и могут содержать:
* соответствует последовательности из 0 или более символов
Заключив в кавычки подстановочный знак *, вы не позволили своей оболочке развернуть его, поэтому она unzip
видит подстановочный знак и выполняет его разворачивание в соответствии со своей собственной логикой.
rm
, напротив, не поддерживает подстановочные знакисам по себе, поэтому попытка заключить в кавычки подстановочный знак приведет к rm
тому, что вместо этого будет выполнен поиск звездочки в имени файла.
Причина, по которой это unzip *.zip
не работает, заключается в том, что unzip
синтаксис просто не допускает использования нескольких zip-файлов; если указано несколько параметров, то ожидается, что второй и последующие будут файлами в архиве:
распаковать [-Z] [-cflptTuvz[abjnoqsCDKLMUVWX$/:^]] файл[.zip] [файл(ы) ...] [-x xfile(s) ...] [-d exdir]
решение2
Разница между этими двумя командами заключается в *
символе кавычек. Если вы вызываете команду в оболочке и используете этот *
символ в качестве аргумента, сама оболочка оценит аргумент. Смотрите этот пример:
$ 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-файлами в качестве аргументов. Но разработчик выбрал для этого другой способ. Из man-страницы:
файл[.zip]
[...] Групповые выражения аналогичны тем, которые поддерживаются в широко используемых оболочках Unix (sh, ksh, csh) [...] (Обязательно заключайте в кавычки все символы, которые могут быть иным образом интерпретированы или изменены операционной системой., особенно в Unix и VMS.)
решение3
Разница в том, что в первом случае оболочка сама расширяет шар:
% 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
...
Если кавычки не указаны, оболочка сначала расширяет глоб, а команда будет выполнена с тем, во что был расширен глоб оболочки.
решение4
Кавычки необходимы из-за способа обработки 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-файлов одновременно, zip поддерживает интерпретацию glob отдельно, с разным результатом.