Объединение нескольких текстовых файлов в один файл в Bash


305

Какой самый быстрый и самый прагматичный способ объединить все файлы * .txt в каталоге в один большой текстовый файл?

В настоящее время я использую Windows с Cygwin, поэтому у меня есть доступ к BASH.

Команда оболочки Windows тоже подойдет, но я сомневаюсь, что она есть.

Ответы:


537

Это добавляет вывод к all.txt

cat *.txt >> all.txt

Это перезаписывает all.txt

cat *.txt > all.txt

30
Вы можете столкнуться с проблемой, когда он переворачивает all.txt в all.txt ... У меня иногда возникает эта проблема с grep, я не уверен, что cat имеет такое же поведение.
rmeador

8
@ rmeador да, это правда, если all.txt уже существует, у вас будет эта проблема. Эта проблема решается путем предоставления выходного файла с другим расширением или перемещения all.txt в другую папку.
Роберт Грайнер

2
cat * .txt >> tmp; mv tmp all.txt (и убедитесь, что all.txt не существует заранее)
Renaud

16
Я получаю «Список аргументов слишком длинный» - думаю, он не может обрабатывать более 40 000 файлов.
Мэтт

32
Избегайте слишком длинного списка аргументов:echo *.txt | xargs cat > all.txt
5heikki

145

Просто помните, что для всех приведенных решений оболочка определяет порядок, в котором файлы объединяются. Для Bash, IIRC, это в алфавитном порядке. Если порядок важен, вы должны либо назвать имена файлов соответствующим образом (01file.txt, 02file.txt и т. Д.) Или указать каждый файл в том порядке, в котором вы хотите его объединить.

$ cat file1 file2 file3 file4 file5 file6 > out.txt

33

Команда оболочки Windows typeможет сделать это:

type *.txt >outputfile

typeКоманда type также записывает имена файлов в stderr, которые не >перехватываются оператором перенаправления (но отображаются на консоли).


2
Просто имейте в виду, что если вы поместите выходной файл в тот же каталог, что и исходный файл, это приведет к дублированию, так как он также объединит новый выходной файл дважды.
CathalMF

26

Вы можете использовать оболочку Windows copyдля объединения файлов.

C:\> copy *.txt outputfile

Из справки:

Чтобы добавить файлы, укажите один файл для места назначения, но несколько файлов для источника (используя подстановочные знаки или формат file1 + file2 + file3).


Это как самое чистое решение ИМХО без каких-либо побочных эффектов, которые могут запутать новички, к сожалению, недостаточно оценены :-(
Grmpfhmbl

ОП попросил Баш.
Большой Богатый

2
Вы читали вопрос? «Команда оболочки Windows тоже подойдет…»
Карл Норум,

8

Будьте осторожны, потому что ни один из этих методов не работает с большим количеством файлов. Лично я использовал эту строку:

for i in $(ls | grep ".txt");do cat $i >> output.txt;done

РЕДАКТИРОВАТЬ: Как кто-то сказал в комментариях, вы можете заменить $(ls | grep ".txt")на$(ls *.txt)

РЕДАКТИРОВАТЬ: благодаря опыту @gnourf_gnourf, использование glob является правильным способом перебора файлов в каталоге. Следовательно, кощунственные выражения вроде $(ls | grep ".txt")должны быть заменены на *.txt(см. Статью здесь ).

Хорошее решение

for i in *.txt;do cat $i >> output.txt;done

1
Почему нет for i in $(ls *.txt);do cat $i >> output.txt;done?
streamofstars

2
Обязательная ссылка ParsingLs вместе с понижением (и вы заслуживаете более одного отклонения, потому что ls | grepэто очень плохой антипаттерн).
gniourf_gniourf

Получил отклик от меня, потому что он допускает произвольное тестирование / операции по имени файла перед выводом, и это быстро, легко и хорошо для практики. (В моем случае я хотел: для i in *; сделать эхо -e "\ n $ i: \ n"; cat $ 1; готово)
Натан Чаппелл

Не будет ли ls *.txtсбой, если файлов слишком много (ошибка списка аргументов слишком длинная)?
Рафаэль Алмейда

6

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

awk '1' *.txt > all.txt
perl -ne 'print;' *.txt > all.txt

1
Это должно быть правильным ответом для большинства обстоятельств. Если какой-либо текстовый файл без пустой новой строки, используя все вышеперечисленные catметоды, конкатенация последней строки и первой строки из соседних файлов
спорный вопрос

6

Как насчет этого подхода?

find . -type f -name '*.txt' -exec cat {} + >> output.txt

Поскольку OP говорит, что файлы находятся в одном и том же каталоге, вам может потребоваться добавить -maxdepth 1в findкоманду.
Codeforester,

1
Прекрасно работает с большим количеством файлов, где подход принятого ответа терпит неудачу
amine

ах, если бы я знал, что означает этот плюс и двойное перенаправление ...
hello_earth

Это должен быть правильный ответ. Это будет работать правильно в сценарии оболочки. Вот аналогичный метод, если вы хотите отсортировать вывод:sort -u --output="$OUTPUT_FILE" --files0-from=- < <(find "$DIRECTORY_NAME" -maxdepth 1 -type f -name '*.txt' -print0)
steveH

3
type [source folder]\*.[File extension] > [destination folder]\[file name].[File extension]

Например:

type C:\*.txt > C:\1\all.txt

Это возьмет все текстовые файлы в папке C: \ и сохранит их в папке C: \ 1 под именем all.txt.

Или

type [source folder]\* > [destination folder]\[file name].[File extension]

Например:

type C:\* > C:\1\all.txt

Это возьмет все файлы, которые присутствуют в папке, и поместит туда содержимое в C: \ 1 \ all.txt.


0

Вы можете сделать так: cat [directory_path]/**/*.[h,m] > test.txt

Если вы используете {}расширение файлов, которые вы хотите найти, возникает проблема последовательности.


0

Когда вы сталкиваетесь с проблемой, в которой он переворачивает all.txt в all.txt, вы можете попробовать проверить, существует ли all.txt или нет, если существует, удалить

Как это:

[ -e $"all.txt" ] && rm $"all.txt"


cat *.txt > all.txt >команда перезаписывает all.txt, если он существует, >>добавляет данные в существующий файл
Олег Бондаренко

-4

все это противно ....

ls | grep *.txt | while read file; do cat $file >> ./output.txt; done;

легкий материал


6
EEEK! Не делай этого. Доfind . -iname "*.txt" -maxdepth 1 -exec cat {} >> out.txt \;
Чинмай Канчи
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.