4

Мне нужно сделать zip-файл, архивирующий ~ 100 тыс. Файлов из каталога, содержащего ~ 500 тыс. Файлов. Я получаю ошибки "список аргументов слишком длинный", когда я пытаюсь выполнить очевидные команды:

zip archive.zip *pattern*.txt                        # fails
zip archive.zip `find . -name "*pattern*.txt"`       # fails

Один из подходов заключается в использовании опции -@ для подачи списка файлов через stdin:

find . -name "*pattern*.txt" | zip -@ archive.zip

Тем не менее, страница руководства zip гласит:

Если список файлов указан как - @ [Не в MacOS], zip берет список входных файлов из стандартного ввода, а не из командной строки.

Меня беспокоит "Не на MacOS". Я пошел вперед и попробовал -@ вариант, и, кажется, работает; но я нервничаю из-за того, что он действительно делает правильную работу (архивирование всех файлов без изменений).

Вот мои вопросы:

  1. Почему бы -@ не быть в порядке на MacOS?
  2. Существуют ли некоторые версии MacOS/bash/zip, где это предупреждение верно, и другие, где это не так? Является ли это устаревшим предупреждением, и если да, то где находится разделительная линия?
  3. Каков жизнеспособный подход к этой проблеме без использования -@?

Обратите внимание, что приведенное здесь решение zip: слишком длинный список аргументов (всего 80 000 файлов) ; Мне нужно архивировать некоторые, а не все файлы в каталоге.

Я использую Mac OS 10.7.5. Вот некоторая информация о версии:

$ bash --version
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11)
$ zip --version
This is Zip 3.0 (July 5th 2008), by Info-ZIP.
...
Compiled with gcc 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00) for Unix (Mac OS X) on Jun 24 2011.

3 ответа3

6

Прежде всего,

zip archive.zip `find . -name "*pattern*.txt"`

это никогда не хорошая идея Имена файлов могут содержать пробелы, символы новой строки, части, которые могут быть интерпретированы как переключатели, и так далее.

Чтобы выполнить действие для каждого найденного файла, вы можете использовать ключ -exec или xargs.

find . -name "*pattern*.txt" -exec zip archive.zip {} +

добавит файлы один за другим в ZIP-файл. Здесь {} символизирует текущий обрабатываемый файл.

Завершение аргумента -exec + вместо ; заставляет find обрабатывать несколько файлов одновременно (столько, сколько может, без генерации тех же самых ошибок, которые вы получаете), что должно быть значительно быстрее для большого количества файлов.

find . -name "*pattern*.txt" -print0 | xargs -0 zip archive.zip

делает по сути то же самое. По умолчанию xargs обрабатывает несколько файлов одновременно.

-print0 для поиска и ключ -0 к xargs заставляют их использовать нулевые символы в качестве разделителей файлов для правильной работы со странными именами файлов.

Я не знаю, почему -@ не рекомендуется для Mac OS 1, но find ... | zip -@ не будет правильно обрабатывать странные имена файлов (в частности, имена файлов, содержащие символы новой строки). Это верно независимо от операционной системы.


1 Я предполагаю, что это применимо только к Mac OS до версии 9.x, поскольку Mac OS использовала возврат каретки в качестве символов новой строки, тогда как zip -@ ожидает перевода строки.

3

Деннис был прав, это вещь OS 9. Я взглянул на исходный код Zip 3.0. В macos/ platform есть примечание, которое говорит:

Этот порт предназначен для версий Mac до Mac OS X. Поскольку Mac OS X основана на Unix, используйте порт Unix для Mac OS X. - 7 июня 2008 г.

Кроме того, файл zip.c оборачивает объявление параметра командной строки в #ifndef MACOS . Другими словами, если бы я использовал zip порт MacOS, опция -@ просто не работала.

Деннис также дал ответ на «жизнеспособный способ выполнить задачу без -@ », а именно:

find . -name "*pattern*.txt" -print0 | xargs -0 zip archive.zip

Я согласен, что это лучший способ действовать, чтобы обезопасить себя от "странных" имен файлов (имен с пробелами, переводом строки и т.д.). Тем не менее, есть снижение производительности. xargs будет вызывать zip несколько раз, каждый раз в качестве параметров командной строки передается большой набор имен файлов. zip будет добавлять эти файлы в archive.zip при каждом вызове. Но zip нужно будет читать все больший archive.zip при каждом вызове, что занимает все больше и больше времени по мере выполнения задания.

Если вы точно знаете , что в именах файлов нет патологических символов, таких как пробелы или символы новой строки, то однопроходный

find . -name "*pattern*.txt" | zip -@ archive.zip

будет быстрее; и он прекрасно работает в OS X, потому что zip в OS X на самом деле является портом Unix. Предупреждение на странице руководства не применяется.

0

Как показывает информация о вашей версии, базовый код (и, следовательно, предположительно документация) довольно старый, за это время MacOS сильно изменилась. Кроме того, сборка намного новее, чем базовый код, могут быть изменения в коде / конфигурации для сборки, которые просто не попали в документацию.

В любом случае лучше проверить (возможно, с небольшим примером), что команда работает и действительно сохраняет файлы, к которым она обращена. Если это важно, не верьте цветным квадратикам с недостающими частями на случайных интернет-сайтах ...

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .