Объединить несколько файлов, но включить имя файла в качестве заголовка раздела


354

Я хотел бы объединить несколько текстовых файлов в один большой файл в терминале. Я знаю, что могу сделать это с помощью команды cat. Однако мне бы хотелось, чтобы имя файла каждого файла предшествовало «дампу данных» для этого файла. Кто-нибудь знает, как это сделать?

что у меня сейчас есть:

file1.txt = bluemoongoodbeer

file2.txt = awesomepossum

file3.txt = hownowbrowncow

cat file1.txt file2.txt file3.txt

желаемый результат:

file1

bluemoongoodbeer

file2

awesomepossum

file3

hownowbrowncow

Я на самом деле использую uuencode & uudecode, чтобы сделать что-то подобное, мне не нужен промежуточный файл для чтения, нужен только результат и снова

Ответы:


532

Искал то же самое, и нашел это, чтобы предложить:

tail -n +1 file1.txt file2.txt file3.txt

Вывод:

==> file1.txt <==
<contents of file1.txt>

==> file2.txt <==
<contents of file2.txt>

==> file3.txt <==
<contents of file3.txt>

Если есть только один файл, то заголовок не будет напечатан. Если вы используете утилиты GNU, вы можете -vвсегда печатать заголовок.


2
Это работает и с хвостом GNU (частью GNU Coreutils).
Арджун Шанкар

8
Отличный -n +1вариант! Альтернатива: head -n-0 file1 file2 file3.
Замороженное пламя

3
Прекрасно работает как с хвостом BSD, так и с хвостом GNU в MacOS X. Вы можете оставить пространство между -nи +1, как в -n+1.
VDM

4
tail -n +1 *именно то, что я искал, спасибо!
kR105

1
работает на MacOsX 10.14.4sudo ulimit -n 1024; find -f . -name "*.rb" | xargs tail -n+1 > ./source_ruby.txt
kolas

187

Я использовал grep для чего-то похожего:

grep "" *.txt

Он не дает вам заголовок, но префикс каждой строки с именем файла.


10
Выходные данные прерываются, если *.txtрасширяется только до одного файла. В связи с этим я бы посоветовалgrep '' /dev/null *.txt
антак

1
+1 за то, что показал мне новое использование grep. это полностью соответствовало моим потребностям. в моем случае каждый файл содержал только одну строку, поэтому он дал мне аккуратно отформатированный вывод, который легко
разбирался

9
grepбудет печатать только заголовки файлов, если существует более одного файла. Если вы хотите всегда печатать путь к файлу, используйте -H. Если вы не хотите использовать заголовки -h. Также обратите внимание, что он будет печатать (standard input)для STDIN.
Хорхе Букаран

1
Вы также можете использовать ag(серебряный искатель): по умолчанию ag . *.txtпрефикс каждого файла имеет свое имя, а каждая строка - свой номер.
анол

1
Следует отметить, что переход -nк grep также дает номера строк, которые позволяют вам писать простые строки с точным указанием, которые могут быть получены, например, emacs.
ДепрессияДаниэль

105

Это также должно помочь:

find . -type f -print -exec cat {} \;

Средства:

find    = linux `find` command finds filenames, see `man find` for more info
.       = in current directory
-type f = only files, not directories
-print  = show found file
-exec   = additionally execute another linux command
cat     = linux `cat` command, see `man cat`, displays file contents
{}      = placeholder for the currently found filename
\;      = tell `find` command that it ends now here

Кроме того, вы можете комбинировать поиски через логические операторы типа -andили -or. find -lsтоже приятно.


1
Не могли бы вы объяснить, что делает эта команда? Это именно то, что мне нужно
AAlvz

5
Это стандартная команда поиска linux. Он ищет все файлы в текущем каталоге, печатает их имя, а затем для каждого, присматривает файл. Пропуск -printне напечатает имя файла перед cat.
Maxim_united

18
Вы также можете использовать -printfдля настройки вывода. Например: find *.conf -type f -printf '\n==> %p <==\n' -exec cat {} \;чтобы соответствовать выводуtail -n +1 *
Maxim_united

1
-printf не работает на Mac, если вы не хотите, brew install findutilsа затем использовать gfindвместо find.
Мэтт Флетчер

2
Если вы хотите цвета, вы можете использовать тот факт, который findпозволяет несколько -execs:find -name '*.conf' -exec printf '\n\e[33;1m%s\e[0m\n' {} \; -exec cat {} \;
Banbh

24

Это должно сделать трюк:

for filename in file1.txt file2.txt file3.txt; do
    echo "$filename"
    cat "$filename"
done > output.txt

или сделать это для всех текстовых файлов рекурсивно:

find . -type f -name '*.txt' -print | while read filename; do
    echo "$filename"
    cat "$filename"
done > output.txt

1
не работал Я только что написал действительно ужасный код awk: для меня в $ listoffiles do awk '{print FILENAME, $ 0, $ 1, $ 2, $ 3, $ 4, $ 5, $ 6, $ 7, $ 8, $ 9, $ 10, $ 11}' $ i >> concat.txt сделано
Ник

2
... хотите уточнить? Это примерно так же просто, как это делает bash.
Крис Эберле

@Nick: ваша строка awk не должна даже работать, учитывая, что $0это целая строка, так что у вас есть повторяющиеся столбцы там ...
Крис Эберле

@Nick: Отличное решение в противном случае :)
Крис Эберле

@ Крис: да, но это намного ужаснее, чем мне бы хотелось. Может быть, ваш код не работает для меня, потому что я использую >>, чтобы поймать стандартный вывод?
Ник

17

У меня была серия файлов, оканчивающихся на stats.txt, которые я хотел объединить с именами файлов.

Я сделал следующее, и когда существует более одного файла, команда «more» включает имя файла в качестве заголовка.

more *stats.txt > stats.txt

или для общего случая

more FILES_TO_CONCAT > OUTPUT_FILE

6
more <FILES> | cat
Acumenus

15
find . -type f -print0 | xargs -0 -I % sh -c 'echo %; cat %'

Это напечатает полное имя файла (включая путь), а затем содержимое файла. Он также очень гибкий, так как вы можете использовать -name "expr" для команды find и запускать столько файлов, сколько вам нужно для файлов.


1
Это также довольно просто в сочетании с grep. Использовать с bash:find . -type f -print | grep PATTERN | xargs -n 1 -I {} -i bash -c 'echo ==== {} ====; cat {}; echo'
Dojuba

5

Мне нравится этот вариант

for x in $(ls ./*.php); do echo $x; cat $x | grep -i 'menuItem'; done

Вывод выглядит так:

./debug-things.php
./Facebook.Pixel.Code.php
./footer.trusted.seller.items.php
./GoogleAnalytics.php
./JivositeCode.php
./Live-Messenger.php
./mPopex.php
./NOTIFICATIONS-box.php
./reviewPopUp_Frame.php
            $('#top-nav-scroller-pos-<?=$active**MenuItem**;?>').addClass('active');
            gotTo**MenuItem**();
./Reviews-Frames-PopUps.php
./social.media.login.btns.php
./social-side-bar.php
./staticWalletsAlerst.php
./tmp-fix.php
./top-nav-scroller.php
$active**MenuItem** = '0';
        $active**MenuItem** = '1';
        $active**MenuItem** = '2';
        $active**MenuItem** = '3';
./Waiting-Overlay.php
./Yandex.Metrika.php

4

Вот как я обычно работаю с форматированием:

for i in *; do echo "$i"; echo ; cat "$i"; echo ; done ;

Я обычно отправляю кота в grep для конкретной информации.


3
Будьте осторожны здесь. for i in *не будет включать подкаталоги.
Acumenus


3

Вы можете использовать эту простую команду вместо цикла for,

ls -ltr | awk '{print $9}' | xargs head

3

Если вам нравятся цвета, попробуйте это:

for i in *; do echo; echo $'\e[33;1m'$i$'\e[0m'; cat $i; done | less -R

или:

tail -n +1 * | grep -e $ -e '==.*'

или: (с установленным пакетом 'multitail')

multitail *

1
Ради цветов find . -type f -name "*.txt" | xargs -I {} bash -c "echo $'\e[33;1m'{}$'\e[0m';cat {}"
выделим

3

Если все файлы имеют одинаковое имя или могут быть сопоставлены find, вы можете сделать (например):

find . -name create.sh | xargs tail -n +1

найти, показать путь и кошку каждого файла.


2

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

Попробуй это

head -n99999999 * или head -n99999999 file1.txt file2.txt file3.txt

надеюсь, это поможет


4
более чистый синтаксис был бы head -n -0 file.txt file2.txt file3.txt. Работает headв GNU coreutils
doubleDown

1

Этот метод напечатает имя файла, а затем содержимое файла:

tail -f file1.txt file2.txt

Вывод:

==> file1.txt <==
contents of file1.txt ...
contents of file1.txt ...

==> file2.txt <==
contents of file2.txt ...
contents of file2.txt ...

3
Это -fполезно, если вы хотите отслеживать файл, в который записывается, но на самом деле не в рамках того, что запросил OP.
Трипли

1

Если вы хотите заменить эти уродливые ==> <== на что-то еще

tail -n +1 *.txt | sed -e 's/==>/\n###/g' -e 's/<==/###/g' >> "files.txt"

объяснение:

tail -n +1 *.txt - вывести все файлы в папку с заголовком

sed -e 's/==>/\n###/g' -e 's/<==/###/g'- заменить ==>на новую строку + ### и<== просто ###

>> "files.txt" - вывести все в файл



0

Если вы хотите получить результат в том же формате, что и желаемый результат, вы можете попробовать:

for file in `ls file{1..3}.txt`; \
do echo $file | cut -d '.' -f 1; \ 
cat $file  ; done;

Результат:

file1
bluemoongoodbeer
file2
awesomepossum
file3
hownowbrowncow

Вы можете поставить echo -eдо и после разреза, чтобы у вас также был интервал между линиями:

$ for file in `ls file{1..3}.txt`; do echo $file | cut -d '.' -f 1; echo -e; cat $file; echo -e  ; done;

Результат:

file1

bluemoongoodbeer

file2

awesomepossum

file3

hownowbrowncow

Пояснение: forцикл проходит по спискуls командой. $ ls file{1..3}.txtРезультат: file1.txt file2.txt file3.txtкаждая итерация будет строка , то она поступает в команду , где я в качестве разделителя полей , который разбивает fileX.txt на две части и печатает field1 (field2 является TXT) Остальное должно быть ясноecho$filecut.
Fekete Шумера

0
  • AIX 7.1 ksh

... на тех, кто уже упомянул голову, работает для некоторых из нас:

$ r head
head file*.txt
==> file1.txt <==
xxx
111

==> file2.txt <==
yyy
222
nyuk nyuk nyuk

==> file3.txt <==
zzz
$

Мне нужно прочитать первую строку; как уже отмечалось, если вы хотите более 10 строк, вам нужно будет добавить опции (head -9999 и т. д.).

Извините за публикацию производного комментария; У меня нет достаточного количества уличных кредитов, чтобы комментировать / добавлять чьи-либо комментарии.


-1

Для решения этой задачи я обычно использую следующую команду:

$ cat file{1..3}.txt >> result.txt

Это очень удобный способ объединения файлов, если количество файлов достаточно велико.


1
Но это не отвечает на вопрос ОП.
Квантур

-3

Сначала я создал каждый файл: echo 'information'> file1.txt для каждого файла [123] .txt.

Затем я распечатал каждый файл, чтобы убедиться, что информация верна: tail file? .Txt

Затем я сделал это: хвостовой файл? .Txt >> Mainfile.txt. Это создало файл Mainfile.txt для хранения информации каждого файла в главном файле.

кот Mainfile.txt подтвердил, что все в порядке.

==> file1.txt <== bluemoongoodbeer

==> file2.txt <== awesomepossum

==> file3.txt <== hownowbrowncow

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.