У меня есть около 15 000 файлов, которые называются file_1.pdb
, file_2.pdb
и т.д. Я могу кот около нескольких тысяч из них в порядке, выполнив:
cat file_{1..2000}.pdb >> file_all.pdb
Однако, если я сделаю это для 15 000 файлов, я получу ошибку
-bash: /bin/cat: Argument list too long
Я видел, как эта проблема решалась, find . -name xx -exec xx
но это не сохраняло бы порядок соединения файлов. Как мне этого добиться?
files
find
cat
brace-expansion
нитрат натрия
источник
источник
cat file_{1..15000}.pdb
конструкция отлично работает для меня.getconf ARG_MAX
должен сказать.Ответы:
Используя
find
,sort
иxargs
:Команда
find
находит все соответствующие файлы, а затем печатает их имена путей,sort
что делает «сортировку версий», чтобы получить их в правильном порядке (если бы числа в именах файлов были заполнены нулями до фиксированной ширины, в которой мы бы не нуждались-V
).xargs
берет этот список отсортированных путей и запускаетcat
их как можно большими партиями.Это должно работать, даже если имена файлов содержат странные символы, такие как переводы строк и пробелы. Мы используем
-print0
с,find
чтобы датьsort
nul-завершенные имена для сортировки, иsort
обрабатывает их, используя-z
.xargs
тоже читает имена с нулем в конце со своим-0
флагом.Обратите внимание, что я записываю результат в файл, имя которого не соответствует шаблону
file_*.pdb
.Вышеупомянутое решение использует некоторые нестандартные флаги для некоторых утилит. Они поддерживаются GNU-реализацией этих утилит и, по крайней мере, OpenBSD и реализацией macOS.
Используются нестандартные флаги
-maxdepth 1
, чтобы сделатьfind
только войти в самый верхний каталог, но без подкаталогов. POSIXly, используйтеfind . ! -name . -prune ...
-print0
, чтобы сделатьfind
выходные имена с нулевым символом в конце (это было рассмотрено POSIX, но отклонено). Можно использовать-exec printf '%s\0' {} +
вместо этого.-z
, чтобы сделатьsort
нуль-завершенные записи. POSIX-эквивалентности нет.-V
, чтобы сделатьsort
сортировку, например,200
после3
. Эквивалентности POSIX не существует, но ее можно заменить числовой сортировкой в определенных частях имени файла, если имена файлов имеют фиксированный префикс.-0
, чтобыxargs
прочитать нуль-завершенные записи. POSIX-эквивалентности нет. POSIXly, нужно было бы заключить в кавычки имена файлов в формате, распознаваемомxargs
.Если имена путей ведут себя хорошо, и если структура каталогов плоская (без подкаталогов), то можно обойтись без этих флагов, кроме как
-V
с помощьюsort
.источник
printf ‘file_%d.pdb\0’ {1..15000} | xargs -0 cat
или даже с точкой зрения Кевинаecho file_{1..15000}.pdb | xargs cat
.find
Решение имеет значительно более накладные расходы , так как он должен искать файловую систему для этих файлов, но это более полезно , когда некоторые файлы могут не существовать.xargs
скорееcat
перенаправляется (каждыйcat
вызов будет использоватьxargs
стандартный вывод). Если бы мы сказали,xargs -0 sh -c 'cat >all.pdb'
то было бы разумно использовать>>
вместо>
, если вы на это намекаете.sort -n -k1.6
будет работать (для оригинала,file_nnn
имен файлов илиsort -n -k1.5
для тех, кто не подчеркивание).С
zsh
(откуда{1..15000}
приходит этот оператор):Или для всех
file_<digits>.pdb
файлов в числовом порядке:(где
<x-y>
не является Глоб оператор , который соответствует по десятичных чисел х у. При отсутствииx
ниy
, это любое десятичное число. Эквивалентextendedglob
«s[0-9]##
илиkshglob
» s+([0-9])
(одна или несколько цифр)).С
ksh93
помощью встроеннойcat
команды (на нее не влияет этот пределexecve()
системного вызова, поскольку нет выполнения ):С
bash
/zsh
/ksh93
(что поддержкаzsh
«s{x..y}
и имеютprintf
встроенный):В системе GNU или совместимой вы также можете использовать
seq
:Для
xargs
решений на основе, особое внимание должно быть уделено именам файлов, которые содержат пробелы, одинарные или двойные кавычки или обратную косую черту.Как для
-It's a trickier filename - 12.pdb
, используйте:источник
seq -f | xarg cat >
самое элегантное и эффективное решение. (ПО МОЕМУ МНЕНИЮ).'"./-It'\''s a trickier filename - %.17g.pdb"'
?Цикл for возможен и очень прост.
Недостатком является то, что вы вызываете
cat
ад много раз. Но если вы не можете точно вспомнить, как с этим работать,find
и затраты на вызовы не так уж и плохи в вашей ситуации, то стоит помнить.источник
echo $i;
в тело цикла в качестве «индикатора прогресса»источник
seq -f file_%.10g.pdb 15000
. Обратите внимание, чтоseq
это не стандартная команда.seq -f
, это отличный способ сделать это; запомню это.посылка
Вы не должны подвергаться этой ошибке только для файлов 15k с определенным форматом имени [ 1 , 2 ] .
Если вы запускаете это расширение из другого каталога и вам нужно добавить путь к каждому файлу, размер вашей команды будет больше, и, конечно, это может произойти.
Решение запустить команду из этого каталога.
Лучшее решение Если вместо этого я угадал, и вы запускаете его из каталога, в котором находятся файлы ...
ИМХО, лучшее решение - это Стефан Шазелас :
с printf или seq; протестировано на 15k файлах, в которых предварительно кэшировано только их число, оно даже быстрее (в настоящее время, за исключением OP из того же каталога, в котором находятся файлы).
Еще несколько слов
Вы должны быть в состоянии передавать командную строку вашей оболочки более долго.
Длина вашей командной строки составляет 213914 символов и содержит 15003 слова
cat file_{1..15000}.pdb " > file_all.pdb" | wc
... даже добавление 8 байт для каждого слова составляет 333 938 байт (0,3 М), намного ниже, чем 2097142 (2,1 МБ), о которых сообщалось
ARG_MAX
в ядре 3.13.0 или немного меньшем 2088232, о котором сообщалось как "Максимальная длина команды, которую мы могли бы на самом деле использовать " поxargs --show-limits
Посмотрите на вашу систему на вывод
Решение для лени
В таких случаях я предпочитаю работать с блоками даже потому, что, как правило, получается эффективное по времени решение.
Логика (если есть) в том, что я слишком ленив, чтобы писать 1 ... 1000 1001..2000 и т. Д.
И т. Д. Поэтому я прошу сценарий сделать это для меня.
Только после того, как я проверил правильность вывода, я перенаправил его в скрипт.
... но лень это состояние души .
Поскольку у меня аллергия на
xargs
(я действительно должен был использоватьxargs
здесь), и я не хочу проверять, как его использовать, я заканчиваю пунктуально, чтобы заново изобрести колесо, как в примерах ниже (tl; dr).Обратите внимание, что, поскольку имена файлов контролируются (без пробелов, новых строк ...), вы можете легко выполнить что-то вроде приведенного ниже сценария.
ТЛ; др
Версия 1: передать в качестве необязательного параметра 1-й номер файла, последний, размер блока, выходной файл
Версия 2
Вызов bash для расширения (немного медленнее в моих тестах ~ 20%).
Конечно, вы можете пойти дальше и полностью избавиться от
seq
[ 3 ] (от coreutils) и работать напрямую с переменными в bash, или использовать python, или скомпилировать программу ac для этого [ 4 ] ...источник
%g
это сокращение от%.6g
. Например, 1 000 + 6 будет представлять 1 000 000.xargs
, ЗШ - йzargs
илиksh93
«scommand -x
.seq
это не встроенная команда bash, это команда из GNU coreutils.seq -f %g 1000000 1000000
выводит 1e + 06 даже в последней версии coreutils.xarg
... но я понимаю, что это личное и, возможно, связано только со мной.Еще один способ сделать это может быть
источник