Заархивировать все файлы в каталоге?

483

Есть ли способ сжать все файлы в данном каталоге с помощью zipкоманды? Я слышал об использовании *.*, но я хочу, чтобы он работал и для файлов без расширений.

tkbx
источник
2
Вы пробовали перейти на один уровень вверх от желаемого каталога и делаете zip myarch.zip mydir/*?
Джозеф Р.
13
или лучшеzip -r myarch.zip mydir/*
Адам
25
или лучшеzip -r myarch.zip mydir
ctrl-alt-delor
*.*означает любой файл с точкой. В cp / m и dos все файлы имеют точку, и это заставляет вас печатать ее (не может сделать *). Поэтому люди пришли посмотреть *.*как все файлы. В конце концов Microsoft добавила длинные имена файлов, которые могли иметь ноль или больше точек. Чтобы найти файл с точкой на окнах, вы должны набрать *.*.*.
ctrl-alt-delor

Ответы:

705

Вы можете просто использовать *; в этом нет необходимости *.*. Расширения файлов не являются специальными в Unix. *соответствует нулю или более символов - включая точку Так что это соответствует foo.png, потому что это ноль или более символов (семь, если быть точным).

Обратите внимание, что *по умолчанию не совпадает с файлами, начинающимися с точки (не совпадает *.*). Это часто то, что вы хотите. Если нет, то в bash, если вы shopt -s dotglobэто сделаете (но все равно исключите .и ..). В других оболочках есть разные способы (или их вообще нет) включения файлов точек.

В качестве альтернативы zipтакже имеется -r(рекурсивная) опция для одновременного создания целых деревьев каталогов (и не нужно беспокоиться о проблеме с точечным файлом):

zip -r myfiles.zip mydir

где mydirнаходится каталог, содержащий ваши файлы. Обратите внимание, что созданный zip-файл будет содержать как структуру каталогов, так и файлы. Как отмечает Петерф в своем комментарии, это обычно рассматривается как хорошая вещь: распаковка zip аккуратно сохранит все извлеченные файлы в одном подкаталоге.

Вы также можете сказать , почтовый индекс , чтобы не сохранять пути с -j/ --junk-pathsопции.

Команда zipпоставляется с документацией, рассказывающей обо всех ее (многих) параметрах; введите, man zipчтобы увидеть эту документацию. Это не уникально для почтового индекса; таким образом вы можете получить документацию для большинства команд.

derobert
источник
9
Вы можете добавить, что рекомендуется хранить все содержимое архива в каталоге верхнего уровня, чтобы при извлечении не загрязнять его / ее текущий каталог.
Петер
@peterph сделано. Боюсь, это менее условно для zip-файлов, чем для tar-файлов.
Дероберт
К сожалению, да. Вероятно, благодаря наследию Windows drag'n'drop для рабочего стола и наследию Linux от работы с исходными кодами.
Петер
2
Имейте в виду, что *глобализация оболочки не включает точечные файлы (т. Е. Имена файлов начинаются с .). Это еще одно преимущество для архивирования всего каталога по имени.
mrb
Но использование -r включает в себя сам каталог, который нарушает то, что я делаю. Не * включить .и ..?
tkbx
11

В моем случае я хотел сжать каждый файл в свой собственный архив, поэтому я сделал следующее (в zsh):

$ for file in *; do zip ${file%.*}.zip $file; done
Радон Росборо
источник
1
Здесь нет mkv? Также здесь нет ничего особенно специфического zsh. Вы захотите правильно заключить в кавычки любую переменную, содержащую имя файла, поэтому zip "${file%.*}.zip" "$file"двойные кавычки вокруг обеих переменных.
tripleee
1
@tripleee Во-первых, спасибо за указание на мою ошибочную ссылку на mkv. Во-вторых, цитирование аргументов не нужно, в zshотличие от bash. Вот почему я указал, что это была команда для zsh.
Радон Росборо
Замена последней точки с запятой амперсандом может значительно ускорить его (если число файлов в каталоге разумно ...). В противном случае find . -type f -maxdepth 1 -print0|xargs -r0 -n1 -P64 -I{} bash -c 'f="{}"; zip "${f%.*}.zip" "$f"'-Pнастройкой в ​​зависимости от потоков вашего процессора ...) (Многие зависимости GNU ...)
Герт ван ден Берг
5

Другим способом было бы использовать find и xargs: (это может включать в себя каталог «.» В zip, но он все равно должен извлекаться правильно. В моем тесте zip удалил точку перед сжатием) find . -type f -exec zip zipfile.zip {} +

( +Можно заменить на, \;если ваша версия findне поддерживает +конец для exec. Хотя это будет медленнее ...)

Это будет по умолчанию включать все подкаталоги. На GNU find -maxdepthможет предотвратить это.

Герт ван ден Берг
источник
(в отличие от используемых решений *, это будет включать в себя точечные файлы и не упадет, если в каталоге слишком много файлов)
Герт ван ден Берг
1

Другой (медленный) метод для этого (который добавляет один файл в zip за раз):

for f in * .[^.]*; do
    [ -r "$f" ] || continue # Skip directories or non-existant files (Probably ".[^.]*" if directory has no dotfiles). Using -e will allow directories to be used as well
    zip zipfile.zip "$f" # If directories are included, you probably want to add -r
done

При этом возникают проблемы с точечным *файлом (добавлено обходное решение), и для каждого файла запускается zip один раз, добавляя его в архив. В bash, это будет иметь дело с большим количеством файлов.

Это будет медленнее, чем большинство других методов, но относительно просто.

Герт ван ден Берг
источник
1
Я бы сказал, что это не так просто, как принятый ответ, и медленнее, что вызывает вопрос: «Зачем кому-то это делать?». Если вы можете ответить на этот вопрос, я рекомендую вам включить этот контекст в свой ответ, в противном случае я думаю, что это плохой ответ на старый вопрос, на который уже есть хороший ответ.
Сентиман
@Centimane: я отмечаю ограничения. Я чувствую, что это имеет образовательную ценность. (Если не пропускать каталоги, это довольно просто). Если вы хотите получить гораздо более быстрый ответ, используя (стандартный) внешний инструмент, мой другой ответ покрывает это. (с удаленной обработкой точечных файлов (которая влияет на корректность без их отсутствия, упомянутых в вопросе), я чувствую, что это довольно элегантно):for f in *; do zip zip.zip "$f"; done
Герт ван ден Берг
1
Обратите внимание, что принятый ответ не использует внешнюю команду и будет быстрее. В каком случае этот ответ будет полезен?
Сентиман
@Centimane С tar, когда файлов больше, чем то, что bash может передать в качестве параметров. (найди + xargs лучше, потому что циклы проще ...). Это (уникальный) ответ на вопрос. Это, конечно, не оптимальный ответ. (Неоптимальные ответы все еще могут быть полезны для аналогичных проблем, если кто-то имеет немного другую ситуацию - например, хочет, чтобы tar-файл содержал какие-либо каталоги в нем)
Герт ван ден Берг