Verketten Sie mehrere Dateien, geben Sie jedoch den Dateinamen als Abschnittsüberschriften an

352

Ich möchte eine Reihe von Textdateien zu einer großen Datei im Terminal verketten. Ich weiß, dass ich dies mit dem Befehl cat tun kann. Ich möchte jedoch, dass der Dateiname jeder Datei vor dem "Datendump" für diese Datei steht. Weiß jemand, wie man das macht?

was ich aktuell habe:

file1.txt = bluemoongoodbeer

file2.txt = awesomepossum

file3.txt = hownowbrowncow

cat file1.txt file2.txt file3.txt

gewünschte Ausgabe:

file1

bluemoongoodbeer

file2

awesomepossum

file3

hownowbrowncow
Nick
quelle
Ich benutze tatsächlich Uuencode & Uudecode, um etwas Ähnliches zu tun. Ich brauche die dazwischen lesbare Datei nicht, brauche nur das Ergebnis und
2
unix.stackexchange.com/questions/12342/…
Ciro Santilli 法轮功 冠状 病. 事件 法轮功

Antworten:

531

War auf der Suche nach dem gleichen Ding und fand dies als Hinweis:

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

Ausgabe:

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

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

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

Wenn nur eine einzige Datei vorhanden ist, wird der Header nicht gedruckt. Wenn Sie GNU-Utils verwenden, können Sie -vimmer einen Header drucken.

DS.
quelle
2
Dies funktioniert auch mit dem GNU-Schwanz (Teil von GNU Coreutils).
ArjunShankar
7
Tolle -n +1Option! Eine Alternative : head -n-0 file1 file2 file3.
Frozen Flame
2
Funktioniert hervorragend mit BSD-Tail und GNU-Tail unter MacOS X. Sie können den Abstand zwischen -nund +1wie in weglassen -n+1.
VDM
4
tail -n +1 *war genau das, wonach ich gesucht habe, danke!
kR105
1
funktioniert auf MacOsX 10.14.4sudo ulimit -n 1024; find -f . -name "*.rb" | xargs tail -n+1 > ./source_ruby.txt
Kolas
186

Ich habe grep für etwas Ähnliches verwendet:

grep "" *.txt

Es gibt Ihnen keinen 'Header', sondern stellt jeder Zeile den Dateinamen voran.

Das Ö
quelle
10
Die Ausgabe wird unterbrochen, wenn *.txtsie nur auf eine Datei erweitert wird. In dieser Hinsicht würde ich ratengrep '' /dev/null *.txt
Antak
1
+1 für das Zeigen einer neuen Verwendung für grep. Dies entsprach perfekt meinen Bedürfnissen. In meinem Fall enthielt jede Datei nur eine Zeile, so dass ich eine ordentlich formatierte Ausgabe erhielt, die leicht zu analysieren war
verboze
9
grepdruckt nur Dateikopfzeilen, wenn mehr als eine Datei vorhanden ist. Wenn Sie sicherstellen möchten, dass der Dateipfad immer gedruckt wird, verwenden Sie -H. Wenn Sie nicht möchten, verwenden Sie die Header -h. Beachten Sie auch, dass es (standard input)für STDIN gedruckt wird.
Jorge Bucaran
1
Sie können auch ag(den silbernen Sucher) verwenden: Standardmäßig wird ag . *.txtjeder Datei der Name und jeder Zeile die Nummer vorangestellt.
Anol
1
Bemerkenswert ist, dass die Übergabe -nan grep auch Zeilennummern ergibt, mit denen Sie einfache Linters mit einer genauen Schreibweise schreiben können, die beispielsweise von Emacs erfasst werden kann.
DepressedDaniel
104

Dies sollte auch den Trick tun:

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

Meint:

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

Sie können Suchvorgänge außerdem über boolesche Operatoren wie -andoder kombinieren -or. find -lsist auch schön

Maxim_united
quelle
1
Können Sie näher erläutern, was dieser Befehl bewirkt? Ist genau das, was ich brauchte
AAlvz
4
Dies ist der Standard-Suchbefehl von Linux. Es durchsucht alle Dateien im aktuellen Verzeichnis, druckt ihren Namen aus und katzt dann für jede Datei die Datei. Wenn Sie das weglassen, -printwird der Dateiname nicht vor dem gedruckt cat.
Maxim_united
17
Sie können auch -printfdie Ausgabe anpassen. Zum Beispiel: find *.conf -type f -printf '\n==> %p <==\n' -exec cat {} \;um die Ausgabe vontail -n +1 *
Maxim_united
1
-printf funktioniert nicht auf dem Mac, es sei denn, Sie möchten brew install findutilsund verwenden gfindstatt find.
Matt Fletcher
1
Wenn Sie Farben wollen, können Sie diese Tatsache verwenden, finddie mehrere -execs erlaubt :find -name '*.conf' -exec printf '\n\e[33;1m%s\e[0m\n' {} \; -exec cat {} \;
Banbh
24

Dies sollte den Trick tun:

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

oder um dies für alle Textdateien rekursiv zu tun:

find . -type f -name '*.txt' -print | while read filename; do
    echo "$filename"
    cat "$filename"
done > output.txt
Chris Eberle
quelle
1
hat nicht funktioniert. Ich habe gerade einen wirklich hässlichen awk-Code geschrieben: für i in $ listoffiles do awk '{print FILENAME, $ 0, $ 1, $ 2, $ 3, $ 4, $ 5, $ 6, $ 7, $ 8, $ 9, $ 10, $ 11}' $ i >> concat.txt fertig
Nick
2
... möchten Sie näher darauf eingehen? Das ist ungefähr so ​​einfach wie Bash-Code.
Chris Eberle
@ Nick: Ihre awk-Zeile sollte nicht einmal funktionieren, wenn man bedenkt, dass dies $0die gesamte Zeile ist, also haben Sie tatsächlich sich wiederholende Spalten darin ...
Chris Eberle
@ Nick: Nifty Lösung sonst :)
Chris Eberle
@ Chris: Ja, aber es ist viel hässlicher als ich es gerne hätte. Vielleicht hat Ihr Code bei mir nicht funktioniert, weil ich >> verwende, um den Standard zu fangen?
Nick
17

Ich hatte eine Reihe von Dateien, die mit stats.txt endeten und die ich mit den Dateinamen verketten wollte.

Ich habe Folgendes getan und wenn es mehr als eine Datei gibt, enthält der Befehl "more" den Dateinamen als Header.

more *stats.txt > stats.txt

oder für einen allgemeinen Fall

more FILES_TO_CONCAT > OUTPUT_FILE
Steinfadt
quelle
5
more <FILES> | cat
Acumenus
15
find . -type f -print0 | xargs -0 -I % sh -c 'echo %; cat %'

Dadurch wird der vollständige Dateiname (einschließlich Pfad) und dann der Inhalt der Datei gedruckt. Es ist auch sehr flexibel, da Sie -name "expr" für den Befehl find verwenden und so viele Befehle ausführen können, wie Sie für die Dateien möchten.

Kevinf
quelle
1
Es ist auch ganz einfach zu kombinieren grep. Zur Verwendung mit bash:find . -type f -print | grep PATTERN | xargs -n 1 -I {} -i bash -c 'echo ==== {} ====; cat {}; echo'
Dojuba
5

Ich mag diese Option

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

Die Ausgabe sieht folgendermaßen aus:

./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
ch3ll0v3k
quelle
4

So gehe ich normalerweise mit der Formatierung um:

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

Normalerweise leite ich die Katze in einen Grep, um bestimmte Informationen zu erhalten.

MorpheousMarty
quelle
3
Sei hier vorsichtig. for i in *enthält keine Unterverzeichnisse.
Acumenus
4

Und die fehlende awk-Lösung lautet:

$ awk '(FNR==1){print ">> " FILENAME " <<"}1' *
kvantour
quelle
Vielen Dank für Ihre tolle Antwort. Können Sie die Bedeutung des 1am Ende des Ausdrucks erklären ?
Bwangel
1
Vielen Dank. Sie können einen Blick auf die Bedeutung von 1 am Ende des awk-Skripts
werfen
3

Sie können diesen einfachen Befehl anstelle einer for-Schleife verwenden.

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

Wenn Sie Farben mögen, versuchen Sie Folgendes:

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

oder:

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

oder: (mit installiertem Paket 'Multitail')

multitail *
sjas
quelle
1
Aus Gründen der Farben, die den Dateinamen hervorheben:find . -type f -name "*.txt" | xargs -I {} bash -c "echo $'\e[33;1m'{}$'\e[0m';cat {}"
MediaVince
3

Wenn die Dateien alle denselben Namen haben oder mit denen sie übereinstimmen können find, können Sie (z. B.) Folgendes tun:

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

Um zu finden, zeigen Sie den Pfad und die Katze jeder Datei.

drkvogel
quelle
2

Hier ist ein wirklich einfacher Weg. Sie sagten, Sie möchten Katze, was bedeutet, dass Sie die gesamte Datei anzeigen möchten. Sie müssen aber auch den Dateinamen ausdrucken.

Versuche dies

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

Ich hoffe, das hilft

Trey Brister
quelle
4
Eine sauberere Syntax wäre head -n -0 file.txt file2.txt file3.txt. Funktioniert für headin GNU Coreutils
DoubleDown
1

Diese Methode druckt den Dateinamen und dann den Dateiinhalt:

tail -f file1.txt file2.txt

Ausgabe:

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

==> file2.txt <==
contents of file2.txt ...
contents of file2.txt ...
serenesat
quelle
3
Dies -fist nützlich, wenn Sie eine Datei verfolgen möchten, in die geschrieben wird, die jedoch nicht im Rahmen der Anforderungen des OP liegt.
Tripleee
1

Wenn Sie diese hässlichen ==> <== durch etwas anderes ersetzen möchten

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

Erläuterung:

tail -n +1 *.txt - Alle Dateien im Ordner mit Header ausgeben

sed -e 's/==>/\n###/g' -e 's/<==/###/g'- ersetzt ==>mit neuer Linie + ### und <==mit nur ###

>> "files.txt" - Alle in eine Datei ausgeben

Boroboris
quelle
0
find . -type f -exec cat {} \; -print
user5689319
quelle
0

Wenn Sie das Ergebnis im gleichen Format wie Ihre gewünschte Ausgabe haben möchten, können Sie Folgendes versuchen:

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

Ergebnis:

file1
bluemoongoodbeer
file2
awesomepossum
file3
hownowbrowncow

Sie können echo -evor und nach dem Schnitt setzen, damit Sie auch den Abstand zwischen den Linien haben:

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

Ergebnis:

file1

bluemoongoodbeer

file2

awesomepossum

file3

hownowbrowncow
Fekete Sumér
quelle
Erläuterung: Die forSchleife durchläuft die Liste, zu der der lsBefehl geführt hat. $ ls file{1..3}.txtErgebnis: Bei file1.txt file2.txt file3.txtjeder Iteration wird echodie $fileZeichenfolge in einen cutBefehl geleitet, den ich .als Feldtrennzeichen verwendet habe. Dabei wird fileX.txt in zwei Teile zerlegt und das Feld1 ausgedruckt (Feld2 ist der txt). Der Rest sollte klar sein
Fekete Sumér
0
  • AIX 7.1 ksh

... auf jene glomming , die bereits erwähnt haben Kopfarbeiten für einige von uns:

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

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

==> file3.txt <==
zzz
$

Ich muss die erste Zeile lesen. Wie bereits erwähnt, müssen Sie, wenn Sie mehr als 10 Zeilen möchten, Optionen hinzufügen (Kopf -9999 usw.).

Entschuldigung für das Posten eines abgeleiteten Kommentars; Ich habe nicht genügend Straßenguthaben, um jemanden zu kommentieren / zu ergänzen.

JustinKaisse
quelle
-1

Zur Lösung dieser Aufgaben verwende ich normalerweise den folgenden Befehl:

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

Es ist eine sehr bequeme Möglichkeit, Dateien zu verketten, wenn die Anzahl der Dateien ziemlich groß ist.

Igor
quelle
1
Dies beantwortet jedoch nicht die Frage des OP.
kvantour
-3

Zuerst habe ich jede Datei erstellt: echo 'information'> file1.txt für jede Datei [123] .txt.

Dann habe ich jede Datei gedruckt, um sicherzustellen, dass die Informationen korrekt waren: Schwanzdatei? .Txt

Dann habe ich folgendes gemacht: tail file? .Txt >> Mainfile.txt. Dadurch wurde die Datei Mainfile.txt erstellt, um die Informationen in jeder Datei in einer Hauptdatei zu speichern.

cat Mainfile.txt bestätigte, dass es in Ordnung war.

==> file1.txt <== bluemoongoodbeer

==> file2.txt <== awesomepossum

==> file3.txt <== hownowbrowncow

John Ray
quelle