Połącz wiele plików, ale podaj nazwę pliku jako nagłówek sekcji


352

Chciałbym połączyć kilka plików tekstowych w jeden duży plik w terminalu. Wiem, że mogę to zrobić za pomocą polecenia cat. Chciałbym jednak, aby nazwa każdego pliku poprzedza „zrzut danych” dla tego pliku. Czy ktoś wie jak to zrobić?

co aktualnie mam:

file1.txt = bluemoongoodbeer

file2.txt = awesomepossum

file3.txt = hownowbrowncow

cat file1.txt file2.txt file3.txt

Pożądane wyjście:

file1

bluemoongoodbeer

file2

awesomepossum

file3

hownowbrowncow

właściwie używam kodu uuencode i uudecode, aby zrobić coś podobnego, nie potrzebuję pliku do odczytu między nimi, potrzebuję tylko wyniku i ponownie

Odpowiedzi:


531

Szukał tego samego i stwierdził, że to sugeruje:

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

Wynik:

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

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

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

Jeśli jest tylko jeden plik, nagłówek nie zostanie wydrukowany. Jeśli używasz narzędzi GNU, możesz użyć, -vaby zawsze wydrukować nagłówek.


2
Działa to również z ogonem GNU (część GNU Coreutils).
ArjunShankar

7
Świetna -n +1opcja! Alternatywą: head -n-0 file1 file2 file3.
Frozen Flame,

2
Działa świetnie zarówno z ogonem BSD, jak i ogonem GNU w MacOS X. Możesz pominąć przestrzeń pomiędzy -ni +1, jak w -n+1.
vdm

4
tail -n +1 *właśnie tego szukałem, dzięki!
kR105

1
działa na MacOsX 10.14.4sudo ulimit -n 1024; find -f . -name "*.rb" | xargs tail -n+1 > ./source_ruby.txt
kolas

186

Użyłem grep do czegoś podobnego:

grep "" *.txt

Nie daje ci „nagłówka”, ale poprzedza każdą linię nazwą pliku.


10
Dane wyjściowe ulegają awarii, jeśli zostaną *.txtrozwinięte tylko do jednego pliku. W związku z tym radziłbymgrep '' /dev/null *.txt
antak

1
+1 za pokazanie mi nowego użycia grep. to doskonale spełniło moje potrzeby. w moim przypadku każdy plik zawierał tylko jedną linię, dzięki czemu otrzymałem starannie sformatowane dane wyjściowe, które można łatwo przetworzyć
czasownik

9
grepwypisze nagłówki plików tylko wtedy, gdy jest więcej niż jeden plik. Jeśli chcesz zawsze drukować ścieżkę pliku, użyj -H. Jeśli nie chcesz używać nagłówków -h. Pamiętaj też, że wydrukuje (standard input)dla STDIN.
Jorge Bucaran

1
Możesz także użyć ag(srebrny wyszukiwarka): domyślnie ag . *.txtpoprzedza każdy plik swoją nazwą i każdą linię jego numerem.
anol

1
Warto zauważyć, że przejście -ndo grep daje również numery linii, które pozwalają pisać proste lintery z dokładnym wskazywaniem, które można wykryć np. Przez emacsa.
Depressed

104

To powinno załatwić sprawę:

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

Znaczy:

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

Ponadto możesz łączyć wyszukiwania za pomocą operatorów logicznych, takich jak -andlub -or. find -lsteż jest miłe.


1
Czy możesz wyjaśnić więcej, co robi to polecenie? Jest dokładnie tym, czego potrzebowałem
AAlvz

4
To jest standardowe polecenie linuxa. Przeszukuje wszystkie pliki w bieżącym katalogu, drukuje ich nazwy, a następnie dla każdego z nich, przechwytuje plik. Pominięcie -printnie spowoduje wydrukowania nazwy pliku przed cat.
Maxim_united

17
Możesz także użyć -printfdo dostosowania danych wyjściowych. Na przykład: find *.conf -type f -printf '\n==> %p <==\n' -exec cat {} \;aby dopasować wyniktail -n +1 *
Maxim_united

1
-printf nie działa na Macu, chyba że chcesz, brew install findutilsa następnie użyjesz gfindzamiast find.
Matt Fletcher

1
Jeśli chcesz kolorów, możesz skorzystać z tego faktu, który findpozwala na wiele -execs:find -name '*.conf' -exec printf '\n\e[33;1m%s\e[0m\n' {} \; -exec cat {} \;
banbh

24

To powinno załatwić sprawę:

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

lub zrobić to rekurencyjnie dla wszystkich plików tekstowych:

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

1
nie działało Właśnie napisałem naprawdę brzydki kod awk: dla i na $ listoffiles do awk '{print FILENAME, 0 $, 1 $, 2, 3 $, 4 $, 5 $, 6, 7 $, 8, 9 $, 10 $, 11}' $ i >> concat.txt zrobione
Nick

2
...Możesz rozwinąć temat? To jest tak proste, jak tylko dostaje się kod bash.
Chris Eberle,

@Nick: twoja linia awk nie powinna nawet działać, biorąc pod uwagę, że $0to jest cała linia, więc faktycznie masz tam powtarzające się kolumny ...
Chris Eberle

@Nick: W przeciwnym razie fajne rozwiązanie :)
Chris Eberle

@Chris: tak, ale jest o wiele brzydszy, niż bym tego chciał. Może twój kod nie działał dla mnie, ponieważ używam >>, aby złapać standardowe wyjście?
Nick

17

Miałem serię plików, które zakończyły się na stats.txt, które chciałem połączyć z nazwami plików.

Wykonałem następujące czynności, a gdy jest więcej niż jeden plik, polecenie „more” zawiera nazwę pliku jako nagłówek.

more *stats.txt > stats.txt

lub w ogólnym przypadku

more FILES_TO_CONCAT > OUTPUT_FILE

5
more <FILES> | cat
Acumenus

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

Spowoduje to wydrukowanie pełnej nazwy pliku (w tym ścieżki), a następnie zawartości pliku. Jest również bardzo elastyczny, ponieważ można użyć -name „expr” dla polecenia find i uruchamiać dowolną liczbę poleceń na plikach.


1
Można go również łatwo połączyć grep. Do użytku z bash:find . -type f -print | grep PATTERN | xargs -n 1 -I {} -i bash -c 'echo ==== {} ====; cat {}; echo'
dojuba

5

Podoba mi się ta opcja

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

Dane wyjściowe wyglądają tak:

./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

Oto jak zwykle radzę sobie z takim formatowaniem:

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

Generalnie podrzucam kota do grepa, żeby uzyskać określone informacje.


3
Uważaj tutaj. for i in *nie będzie zawierać podkatalogów.
Acumenus


3

możesz użyć tej prostej komendy zamiast pętli for,

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

3

Jeśli lubisz kolory, spróbuj tego:

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

lub:

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

lub: (z zainstalowanym pakietem „multitail”)

multitail *

1
Ze względu na kolory podkreślające nazwę pliku:find . -type f -name "*.txt" | xargs -I {} bash -c "echo $'\e[33;1m'{}$'\e[0m';cat {}"
MediaVince

3

Jeśli wszystkie pliki mają tę samą nazwę lub można je dopasować find, możesz (np.):

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

znaleźć, pokazać ścieżkę i cat każdego pliku.


2

Oto naprawdę prosty sposób. Powiedziałeś, że chcesz cat, co oznacza, że ​​chcesz wyświetlić cały plik. Ale musisz także wydrukować nazwę pliku.

Spróbuj tego

head -n99999999 * lub head -n99999999 file1.txt file2.txt file3.txt

Mam nadzieję, że to pomaga


4
czystsza składnia byłaby head -n -0 file.txt file2.txt file3.txt. Działa headw
jądrach

1

Ta metoda wydrukuje nazwę pliku, a następnie zawartość pliku:

tail -f file1.txt file2.txt

Wynik:

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

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

3
Jest -fto przydatne, jeśli chcesz śledzić plik, w którym jest zapisywany, ale tak naprawdę nie mieści się w zakresie tego, o co poprosił PO.
tripleee

1

Jeśli chcesz zastąpić te brzydkie ==> <== czymś innym

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

wyjaśnienie:

tail -n +1 *.txt - wypisuje wszystkie pliki w folderze z nagłówkiem

sed -e 's/==>/\n###/g' -e 's/<==/###/g'- wymienić ==>z nowej linii + ### oraz <==z zaledwie ###

>> "files.txt" - wypisuje wszystko do pliku



0

Jeśli chcesz uzyskać wynik w tym samym formacie, co pożądany wynik, możesz spróbować:

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

Wynik:

file1
bluemoongoodbeer
file2
awesomepossum
file3
hownowbrowncow

Możesz umieścić echo -eprzed i po cięciu, aby mieć również odstępy między liniami:

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

Wynik:

file1

bluemoongoodbeer

file2

awesomepossum

file3

hownowbrowncow

Objaśnienie: forpętla przechodzi przez listę wynikającą z lspolecenia. $ ls file{1..3}.txtRezultat: file1.txt file2.txt file3.txtkażda iteracja będzie ciąg potem to rurami do komendy, gdzie używany jako separator pól, które łamie fileX.txt na dwie części i wypisuje pole1 (pole2 jest txt) Reszta powinna być jasneecho$filecut.
Fekete Sumer

0
  • AIX 7.1 ksh

... glomming na tych, którzy już wspominali, że głowa działa dla niektórych z nas:

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

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

==> file3.txt <==
zzz
$

Potrzebuję przeczytać pierwszą linię; jak wspomniano, jeśli chcesz mieć więcej niż 10 linii, musisz dodać opcje (head -9999 itp.).

Przepraszamy za opublikowanie komentarza pochodnego; Nie mam wystarczających danych ulicznych do komentowania / dodawania do czyichś komentarzy.


-1

Do rozwiązania tego zadania zwykle używam następującego polecenia:

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

Jest to bardzo wygodny sposób na łączenie plików, jeśli liczba plików jest dość duża.


1
Ale to nie odpowiada na pytanie PO.
kvantour

-3

Najpierw utworzyłem każdy plik: echo „informacje”> plik1.txt dla każdego pliku [123] .txt.

Następnie wydrukowałem każdy plik, aby upewnić się, że informacje są prawidłowe: plik ogona? .Txt

Potem zrobiłem to: plik tail? .Txt >> Mainfile.txt. To utworzyło plik Mainfile.txt do przechowywania informacji w każdym pliku w pliku głównym.

cat Mainfile.txt potwierdził, że wszystko jest w porządku.

==> plik1.txt <== bluemoongoodbeer

==> plik2.txt <== awesomepossum

==> plik3.txt <== hownowbrowncow

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.