Множество текстовых файлов в один большой текстовый файл

Множество текстовых файлов в один большой текстовый файл

Я хочу объединить тысячи маленьких текстовых файлов в один большой текстовый файл. Они у меня в каталогах со структурой: timestamp1/status.txt. Например: 20130430133144/status.txt. Пока что я знаю, что

cat */* > bigtextfile.txt

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

решение1

В:

cat */* > bigtextfile.txt

Оболочка расширится */*до отсортированного списка (не скрытых) соответствующих файлов и выполнит команду catс указанием путей к этим файлам в качестве аргументов.

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

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

Для этого можно использовать xargs(здесь с GNU или BSD xargsдля нестандартных -rопций -0):

printf '%s\0' */* | xargs -r0 cat -- > big-file.txt

(поскольку printfвстроен в оболочку, он не проходит через execveсистемный вызов, а значит, и через его предел).

Или findсоставьте список файлов и выполните столько команд cat, сколько необходимо:

find . -mindepth 2 -maxdepth 2 -type f -exec cat {} + > big-file.txt

Или переносимо:

find . -path './*/*' -prune -type f -exec cat {} + > big-file.txt

(однако следует помнить, что в отличие от */*, он будет включать скрытые файлы (и файлы в скрытых каталогах), а не искать файлы в символических ссылках на каталоги, и список файлов не будет отсортирован).

Если вы используете последнюю версию Linux, вы можете снять ограничение на размер аргументов, выполнив:

ulimit -s unlimited
cat -- */* > big-file.txt

С zsh, вы также можете использовать zargs:

autoload zargs
zargs -- */* -- cat > big-file.txt

С помощью ksh93вы можете использовать command -x:

command -x cat -- */* > big-file.txt

Все они делают одно и то же: разбивают список файлов и запускают столько catкоманд, сколько необходимо.

Опять ksh93же, обойти ограничение можно execve()с помощью встроенной catкоманды:

command /opt/ast/bin/cat -- */* > big-file.txt

решение2

Нет catне будет буферизовать все файлы перед началом записи.

Однако если у вас большое количество файлов, вы можете столкнуться с проблемой с количеством переданных аргументов cat. По умолчанию ядро ​​Linux позволяет передавать любой программе только фиксированное количество аргументов (я не помню, как получить это значение, но в большинстве случаев это несколько тысяч).
Чтобы решить эту проблему, вы можете сделать что-то вроде этого:

find -mindepth 2 -maxdepth 2 -type f -exec cat {} \; > bigtextfile.txt

По сути, это будет вызываться catотдельно для каждого файла, найденного find.

решение3

Если количество файлов слишком велико, то */*будет выдан слишком большой список аргументов. Если так, то подойдет что-то вроде этого:

find . -name "*.txt" | xargs cat > outfile

(идея состоит в том, чтобы использовать findдля сбора имен файлов и преобразования их в поток; xargsразбивает этот поток на управляемые части, чтобы передать их в cat, который объединяет их в выходной поток xargs, а тот отправляется в outfile).

Связанный контент