Почему не все файлы сжаты и как улучшить решение

8

У меня есть папка с около 20K файлов. Файлы названы в соответствии с шаблоном xy_{\d1,5}_{\d4}\.abc, например xy_12345_1234.abc. Я хотел сжать первые 10K из них с помощью этой команды:

ls | sort -n -k1.4,1.9 | head -n10000 | xargs tar -czf xy_0_10000.tar.gz

однако полученный файл содержал только около 2K файлов.

ls | sort -n -k1.4,1.9 | head -n10000 | wc -l однако возвращает 10000, как и ожидалось.

Мне кажется, что я здесь неправильно что-то понимаю ...

Я использую zsh 5.0.2 на Linux Mint 17.1, GNU tar 1.27.1

РЕДАКТИРОВАТЬ:

разветвление в соответствии с предложением @Archemar звучит очень правдоподобно, с последним форком, перезаписывающим полученный файл - файл содержит «хвост» файлов - от 7773 до 9999 .

результат xargs --show-limit: Your environment variables take up 3973 bytes POSIX upper limit on argument length (this system): 2091131 POSIX smallest allowable upper limit on argument length (all systems): 4096 Maximum length of command we could actually use: 2087158 Size of command buffer we are actually using: 131072

замена -cс -rили -uне работает в моем случае. Сообщение об ошибке былоtar: Cannot update compressed archives

использование обоих -rи -uнедопустимо и терпит неудачу сtar: You may not specify more than one '-Acdtrux', '--delete' or '--test-label' option

замена -cна, -aкажется, также недействительна и терпит неудачу с тем же самым, tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' optionsхотя я не признаю проблему azfи Acdtruxкажется мне несвязной.

РЕДАКТИРОВАТЬ 2:

-Т выглядит неплохо, я также нашел пример здесь .

Однако, когда я пытаюсь

ls | sort -n -k1.4,1.9 | head -n10000 | tar -czf xy_0_10000.tar.gz -T - я получил tar: option requires an argument -- 'T'

ну, возможно, имена файлов не доходят до tar? Но похоже, что они делают, потому что, когда я выполняю

ls | sort -n -k1.4,1.9 | head -n10000 | tar --null -czf xy_0_10000.tar.gz -T - я получил tar: xy_0_.ab\nxy_1_...<the rest of filenames separated by literal \n>...998.ab Cannot stat: File name too long

Так почему tar не видит имена файлов?

Kostja
источник
а если вы попробуете вместо c, в команде tar?
Оливье Дюлак
5
Соответствующий: не анализируйте выходные данныеls
8bittree
1
У файла OP нет хитрых имен.
Архемар
@ 8bittree - да, в общем, совет для надежных сценариев оболочки, да. но что вы предлагаете вместо этого для работы со списками файлов с обычными одноразовыми подписчиками?
Костя
1
Я бы использовал @kostja find, у которого есть -print0возможность использовать нулевой байт в качестве разделителя вместо новой строки. sortможет справиться с этим с -zфлагом. headК сожалению, не обрабатывает понимать нулевые байтовые разделители, но этот ответ имеет решение использовать trдля замены \nи \0до и после head. tarдолжен --null -T -читать имена файлов с нулевым разделителем stdin.
8bittree

Ответы:

12

вы достигли предела xargs?

xargs --show-limit

пытаться :

  • создать фиктивный .tgzфайлtar czf xy_0_10000.tar.gz /hello/world
  • заменить -czfна -Azf

когда xarg достигнет своего предела, он выполнит команду fork, поэтому команда, которую вы запустили ультимативно, была

  tar czf xy_0_10000.tar.gz file1 file2 .... file666
  tar czf xy_0_10000.tar.gz file667 file668 ... file1203
  tar czf xy_0_10000.tar.gz file1024 ... file2000

как и каждый предыдущий смола, вы можете получить только последний tar cзапуск.

Редактировать:

1) в соответствии с man tarunbuntu, -aи -r кажется эквивалентным, добавление выполняется (либо) -A, --catenate, --concatenate

2) zip(не gzip) можно использовать для добавления файла, возможно, вариант gzip поможет. (используйте | xargs zip -qr xy_0_0000.zip, это приведет к zip-файлу, а не к .tar.gz)

3) использовать решение @ rsanchez.
Важно правильно добавить опцию в tar, попробуйте

ls | sort -n -k1.4,1.9 | head -n10000 |tar -czf xy_0_10000.tar.gz -T -

где - -T -означает использовать опцию -Tи использовать в -качестве аргумента -T(вы могли бы создать список файлов /tmp/foo.lst, затем использовать -T /tmp/foo.lst)

Archemar
источник
может ли (= добавить) вместо c (= создать / перезаписать) обойти это ограничение?
Оливье Дюлак,
@OlivierDulac ( Предупреждение: это чистое предположение ) Вероятно, это не решит проблему, поскольку tar не может создавать пустые файлы. Вы можете сначала сжать пустую папку и использовать a (add)для добавления файлов в файл tar. Затем вы можете открыть tar и удалить папку (используя 7zip или что-то еще)
Ismael Miguel
@ismaelmiguel: я уверен, что он с удовольствием создаст файл. если нет, просто:touch xy_0_10000.tar.gz && { _the full command here_ ; }
Оливье Дюлак
1
@OlivierDulac Это будет неверный .gzфайл.
Исмаэль Мигель
Все man-страницы, которые я вижу на manpages.ubuntu.com/manpages/vivid/en/man1/tar.1.html ( 15.04 ), вернее (12.04) имеют -rдобавление, но -aавтоматическое сжатие, которое не эквивалентно. И -rzне работает: zipможет добавить к существующему архиву, потому что каталог не сжимается, а tarпри сжатии сжимает метаданные вместе с данными. Вы можете по tar -rкусочкам в несжатый архив и затем сжать результат. Или ...
dave_thompson_085
12

Там нет необходимости xargs. Если вы сразу даете tarв -T -опции он будет читать имена файлов из стандартного ввода.

Например:

... | tar -T - -czf xy_0_10000.tar.gz
rsanchez
источник
Я, кажется, неправильно использую опцию, не могу заставить ее работать с конвейером. Пытался ...| tar Tczf xy_..., ...| tar Tcz -f xy_... ...| tar -czf xy_... -T и несколько других перестановок, но я получаю только tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' options, tar: -f: Cannot stat: No such file or directoryесли используется -fотдельно от других вариантов и tar: option requires an argument -- 'T'. Не могли бы вы добавить пример использования?
Костя
Добавлен пример @kostja.
rsanchez
Большое спасибо, rsanchez. Не уверен, почему вариант с -T -в конце tarсписка опций не работал, но ваш пример сработал. К сожалению, мой вопрос фактически состоял из двух частей - источника ошибки и возможного улучшения. В то время как вы справились с последним, Archemar преуспел в первом и почти имел право последнего. Я не уверен, какой из ваших ответов принять, поскольку они оба, очевидно, были полезны.
Костя
1

Я хочу дополнить два других ответа решением zsh , которое не разбирает ls и не нуждается в xargs . Однако сейчас я не уверен, страдает ли это также от ограничения длины командной строки.

  1. Определите функцию, которая генерирует нужный ключ сортировки путем изменения $REPLY.

    sortkey() { REPLY=${REPLY[4,9]} }

    Это эквивалентно вашему sort -n -k1.4,1.9

  2. Создайте массив $filesс именами файлов, отсортированными с помощью вышеуказанной функции:

    files=(*(o+sortkey))

    Это эквивалентно ls | sort -n -k1.4,1.9

  3. Верните первые 10 000 файлов с

    ${files[0,9999]}

    Это эквивалентно ls | sort -n -k1.4,1.9 | head -n10000

Итак, все это должно сделать свое дело:

sortkey() { REPLY=${REPLY[4,9]} }
files=(*(o+sortkey))
tar -czf xy_0_10000.tar.gz ${files[0,9999]}
МРУ
источник