Как вы можете распаковать более одного файла одновременно?

У меня есть куча tar файлов в каталоге, и я хочу извлечь из них все файлы сразу. Но это, похоже, ничего не делает:

$ tar xf *.tar

Что тут происходит? Как распаковать сразу кучу файлов?


person Jon Ericson    schedule 24.02.2009    source источник


Ответы (3)


Что тут происходит?

Первоначально команда tar предназначалась для использования с устройствами с магнитной лентой. Поскольку имело смысл выполнять tar только на одном устройстве за раз, синтаксис был разработан для предположения об одном и только одном устройстве. Предполагалось, что первым переданным файлом или каталогом будет устройство, на котором хранится рассматриваемый архив, а также любые другие файлы или каталоги, в которых содержимое архива должно быть включено в операцию. Таким образом, для извлечения tar (опция x) первый переданный файл будет архивом, а все остальные файлы будут файлами для извлечения. Итак, если есть два файла *.tar (скажем, a.tar и b.tar), ваша команда расширится до:

$ tar xf a.tar b.tar

Если a.tar не содержит файл с именем b.tar, команда tar ничего не делает и тихо завершает работу. Досадно, что версия tar для Solaris не сообщает о каких-либо проблемах ни в коде возврата, ни в подробном параметре (v). Между тем, GNU tar возвращает 2 и рассылает спам STDERR даже при отключенной опции verbose:

tar: b.tar: Not found in archive
tar: Exiting with failure status due to previous errors

Как распаковать сразу кучу файлов?

Слишком поздно переписывать tar, чтобы принимать несколько архивных файлов в качестве входных данных, но обойти это ограничение несложно.

Для большинства людей запуск tar несколько раз для нескольких архивов является наиболее целесообразным вариантом. Передача всего одного имени файла в tar xf приведет к извлечению всех заархивированных файлов, как и следовало ожидать. Один из подходов заключается в использовании цикла оболочки for:

$ for f in *.tar; do tar xf "$f"; done

Другой способ — использовать xargs:

$ ls *.tar | xargs -i tar xf {}

Кроме того, вы можете использовать одну из нескольких альтернативных tar программ чтения файлов. . Наконец, по-настоящему увлеченный программист может легко написать замену tar, которая будет работать именно так, как нужно. формат прост, и многие языки программирования имеют библиотеки для чтения tar файлов. . Например, если вы программист Perl, взгляните на модуль Archive::Tar.

Предупреждение

Слепое распаковывание кучи файлов может привести к непредвиденным проблемам. Наиболее очевидным является то, что конкретное имя файла может быть включено более чем в один файл tar. Поскольку tar по умолчанию перезаписывает файлы, точная версия файла, который у вас получится, будет зависеть от порядка обработки архивов. Что еще более тревожно, вы можете получить поврежденную копию файла, если попробуете эту «умную» оптимизацию:

for f in *.tar; do
  tar xf "$f" &
done
wait

Если и a.tar, и b.tar содержат один и тот же файл и попытаются извлечь его одновременно, результаты будут непредсказуемыми.

Связанная с этим проблема, особенно при получении архивов из ненадежного источника, связана с возможностью tarbomb.

Одним из частичных решений было бы автоматическое создание нового каталога для извлечения в:

for f in *.tar; do 
  d=`basename "$f" .tar`
  mkdir "$d"
  (cd "$d" && tar xf "../$f")
done

Это не поможет, если файл в архиве указан с абсолютным путем (что обычно является признаком злого умысла). Добавление такой проверки оставлено читателю в качестве упражнения.

person Jon Ericson    schedule 24.02.2009
comment
Моя справочная страница tar говорит, что параметры -l и -i появляются в версии стандарта POSIX 1997 года, но не появляются в версии стандарта 2004 года. Поэтому вместо этого следует использовать -L и -I соответственно. Для этой задачи я был бы осторожен с xargs и использовал -n1, чтобы избежать исходной проблемы. - person slacy; 25.02.2009
comment
@slacy: я думаю, вы имеете в виду справочную страницу GNU xargs. Полагаю, вы правы, но мне очень не нравится, как получится: xargs -I {} tar xf {}. С другой стороны, -n1 отлично работает в этом случае: | xargs -n1 tar tf. Это даже улучшение. Но это новый трюк для этой старой собаки. ;-) - person Jon Ericson; 25.02.2009
comment
Отличный ответ, но я хотел бы добавить, что если один из tar содержит пробелы, это не удастся, если мы не заключим в кавычки параметр tar: for f in *.tar; do tar xf "$f"; done - person Enoon; 09.03.2016
comment
Отличное объяснение! - person information_interchange; 15.06.2018

Если все файлы tar находятся в одной папке, то я делаю это в оболочке tcsh. Работает все время.

find -iname \*.tar -exec tar -xvf {} \;

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

person Snehashis Roy    schedule 31.12.2015

person    schedule
comment
Объяснение того, что делает код, было бы полезно! - person DNKROZ; 12.06.2014