Об’єднайте декілька файлів, але додайте ім'я файлу як заголовки розділів


352

Я хотів би об'єднати декілька текстових файлів у один великий файл у терміналі. Я знаю, що можу це зробити за допомогою команди 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, щоб зробити щось подібне, мені не потрібен файл, читабельний між ними, потрібен лише результат і знову

Відповіді:


531

Шукав те саме, і знайшов це, щоб підказати:

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).
ArjunShankar

7
Дивовижний -n +1варіант! Альтернатива: head -n-0 file1 file2 file3.
Заморожене полум'я

2
Відмінно працює як з хвостом 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
Колас

186

Я використовував grep для чогось подібного:

grep "" *.txt

Він не дає вам "заголовка", але префіксує кожен рядок із назвою файлу.


10
Вихід розбивається, якщо *.txtрозширюється лише на один файл З цього приводу я б радивgrep '' /dev/null *.txt
antak

1
+1 за показ мені нового використання grep. це чудово відповідало моїм потребам. у моєму випадку кожен файл містив лише один рядок, тому він дав мені чітко відформатований вихід, який легко був
проаналізований

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

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

1
Зверніть увагу, що перехід -nдо grep також дає номери рядків, що дозволяє писати прості підводки з чіткою точкою, які можуть бути вибрані, наприклад, emacs.
Пригнічений

104

Сюди також слід виконати трюк:

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

4
Це стандартна команда пошуку Linux. Він здійснює пошук усіх файлів у поточному каталозі, друкує їх ім’я, потім для кожного з них видає кішку. Якщо -printви не будете друкувати ім'я файлу перед cat.
Maxim_united

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

1
-printf не працює на mac, якщо ви не хочете, brew install findutilsа потім використовуєте gfindзамість find.
Метт Флетчер

1
Якщо ви хочете кольорів, ви можете використовувати той факт, який 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це весь рядок, тому у вас насправді є стовпці, що повторюються,
Chris Eberle

@Nick: Рішення Nifty інакше :)
Кріс Еберл

@Chris: так, але це набагато хижіше, ніж я хотів би. Можливо, ваш код не працював для мене, тому що я використовую >>, щоб зловити stdout?
Нік

17

У мене була серія файлів, які закінчилися stats.txt, які я хотів з'єднати з іменами файлів.

Я зробив наступне, і коли є більше одного файлу, команда "більше" включає ім'я файлу як заголовка.

more *stats.txt > stats.txt

або для загального випадку

more FILES_TO_CONCAT > OUTPUT_FILE

5
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 ;

Я, як правило, кота вкладає в греп для конкретної інформації.


3
Будьте обережні тут. for i in *не включатимуть підкаталоги.
Акумен


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 *

1
Заради кольорів, що підкреслюють назву файлу:find . -type f -name "*.txt" | xargs -I {} bash -c "echo $'\e[33;1m'{}$'\e[0m';cat {}"
MediaVince

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корисно, якщо ви хочете відслідковувати файл, до якого записується, але насправді не в межах того, про що попросила ОП.
tripleee

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 кш

... поглянувши на тих, хто вже згадував, голова працює для деяких із нас:

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

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

==> file3.txt <==
zzz
$

Моя потреба - прочитати перший рядок; як зазначалося, якщо вам потрібно більше 10 рядків, вам доведеться додати параметри (голова -9999 тощо).

Вибачте за публікацію похідного коментаря; У мене немає достатньої вуличної довіри, щоб коментувати / додати до коментаря когось.


-1

Для вирішення цього завдання зазвичай використовую таку команду:

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

Це дуже зручний спосіб об'єднання файлів, якщо кількість файлів досить велика.


1
Але це не відповідає на питання ОП.
kvantour

-3

Спочатку я створив кожен файл: echo 'information'> file1.txt для кожного файлу [123] .txt.

Потім я надрукував кожен файл, щоб переконатися, що інформація була правильною: хвостовий файл? .Txt

Тоді я зробив це: хвостовий файл? .Txt >> Mainfile.txt. Це створило Mainfile.txt для зберігання інформації в кожному файлі в основний файл.

cat mainfile.txt підтвердив, що це добре.

==> file1.txt <== bluemoongoodbeer

==> file2.txt <== awesomepossum

==> file3.txt <== hownowbrowncow

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.