Concaténer plusieurs fichiers mais inclure le nom de fichier comme en-têtes de section

354

Je voudrais concaténer un certain nombre de fichiers texte en un seul grand fichier dans le terminal. Je sais que je peux le faire en utilisant la commande cat. Cependant, je voudrais que le nom de fichier de chaque fichier précède le "vidage de données" pour ce fichier. Quelqu'un sait-il comment faire ça?

ce que j'ai actuellement:

file1.txt = bluemoongoodbeer

file2.txt = awesomepossum

file3.txt = hownowbrowncow

cat file1.txt file2.txt file3.txt

Sortie désirée:

file1

bluemoongoodbeer

file2

awesomepossum

file3

hownowbrowncow
pseudo
la source
j'utilise en fait uuencode et uudecode pour faire quelque chose de similaire, je n'ai pas besoin du fichier lisible entre eux, j'ai seulement besoin du résultat et
2
unix.stackexchange.com/questions/12342/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Réponses:

532

Cherchait la même chose, et a trouvé cela pour suggérer:

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

Production:

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

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

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

S'il n'y a qu'un seul fichier, l'en-tête ne sera pas imprimé. Si vous utilisez des utilitaires GNU, vous pouvez utiliser -vpour toujours imprimer un en-tête.

DS.
la source
2
Cela fonctionne également avec la queue GNU (qui fait partie de GNU Coreutils).
ArjunShankar
8
Super -n +1option! Une alternative: head -n-0 file1 file2 file3.
Frozen Flame
3
Fonctionne très bien avec la queue BSD et la queue GNU sur MacOS X. Vous pouvez laisser de l'espace entre -net +1, comme dans -n+1.
vdm
4
tail -n +1 *était exactement ce que je cherchais, merci!
kR105
1
fonctionne sur MacOsX 10.14.4sudo ulimit -n 1024; find -f . -name "*.rb" | xargs tail -n+1 > ./source_ruby.txt
kolas
187

J'ai utilisé grep pour quelque chose de similaire:

grep "" *.txt

Il ne vous donne pas un «en-tête», mais préfixe chaque ligne avec le nom de fichier.

Théo
la source
10
La sortie est interrompue si elle n'est *.txtétendue qu'à un seul fichier. À cet égard, je conseilleraisgrep '' /dev/null *.txt
antak
1
+1 pour me montrer une nouvelle utilisation de grep. cela répondait parfaitement à mes besoins. dans mon cas, chaque fichier ne contenait qu'une seule ligne, donc cela m'a donné une sortie bien formatée qui était facilement analysable
verboze
9
grepn'imprimera les en-têtes de fichier que s'il existe plusieurs fichiers. Si vous voulez vous assurer d'imprimer toujours le chemin du fichier, utilisez -H. Si vous ne voulez pas utiliser les en-têtes -h. Notez également qu'il sera imprimé (standard input)pour STDIN.
Jorge Bucaran
1
Vous pouvez également utiliser ag(le chercheur argenté): par défaut, ag . *.txtpréfixe chaque fichier avec son nom, et chaque ligne avec son numéro.
anol
1
Il est à noter que le passage -nà grep donne également des numéros de ligne qui vous permettent d'écrire des linters simples avec un repérage qui pourraient être récupérés par exemple par emacs.
DepressedDaniel
105

Cela devrait aussi faire l'affaire:

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

Veux dire:

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

Vous pouvez en outre combiner des recherches à travers des opérateurs booléens comme -andou -or. find -lsc'est bien aussi.

Maxim_united
la source
1
Pourriez-vous expliquer davantage ce que fait cette commande? C'est exactement ce dont j'avais besoin
AAlvz
5
Il s'agit de la commande find standard de linux. Il recherche tous les fichiers du répertoire courant, imprime leur nom, puis pour chacun, cat le fichier. L'omission de -printn'imprimera pas le nom de fichier avant le cat.
Maxim_united
18
Vous pouvez également utiliser -printfpour personnaliser la sortie. Par exemple: find *.conf -type f -printf '\n==> %p <==\n' -exec cat {} \;pour faire correspondre la sortie detail -n +1 *
Maxim_united
1
-printf ne fonctionne pas sur mac, sauf si vous le souhaitez brew install findutils, puis utilisez gfindau lieu de find.
Matt Fletcher
2
Si vous voulez des couleurs, vous pouvez utiliser ce fait qui findpermet plusieurs -execs:find -name '*.conf' -exec printf '\n\e[33;1m%s\e[0m\n' {} \; -exec cat {} \;
banbh
24

Cela devrait faire l'affaire:

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

ou pour faire ceci pour tous les fichiers texte récursivement:

find . -type f -name '*.txt' -print | while read filename; do
    echo "$filename"
    cat "$filename"
done > output.txt
Chris Eberle
la source
1
n'a pas fonctionné. Je viens d'écrire du code awk vraiment moche: pour i dans $ listoffiles do awk '{print FILENAME, $ 0, $ 1, $ 2, $ 3, $ 4, $ 5, $ 6, $ 7, $ 8, $ 9, $ 10, $ 10, $ 11}' $ i >> concat.txt done
Nick
2
... vous voulez élaborer? C'est à peu près aussi simple que le code bash.
Chris Eberle
@Nick: votre ligne awk ne devrait même pas fonctionner, étant donné que $0 c'est toute la ligne, donc vous avez en fait des colonnes répétitives là-dedans ...
Chris Eberle
@Nick: Solution astucieuse autrement :)
Chris Eberle
@Chris: oui, mais c'est beaucoup plus laid que je ne le souhaiterais. Peut-être que votre code ne fonctionnait pas pour moi parce que j'utilise >> pour attraper la sortie standard?
Nick
17

J'avais une série de fichiers qui se terminaient par stats.txt que je voulais concaténer avec les noms de fichiers.

J'ai fait ce qui suit et lorsqu'il y a plus d'un fichier, la commande "more" inclut le nom de fichier comme en-tête.

more *stats.txt > stats.txt

ou pour un cas général

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

Cela affichera le nom de fichier complet (y compris le chemin d'accès), puis le contenu du fichier. Il est également très flexible, car vous pouvez utiliser -name "expr" pour la commande find et exécuter autant de commandes que vous le souhaitez sur les fichiers.

kevinf
la source
1
Il est également assez simple de combiner avec grep. A utiliser avec bash:find . -type f -print | grep PATTERN | xargs -n 1 -I {} -i bash -c 'echo ==== {} ====; cat {}; echo'
dojuba
5

J'aime cette option

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

La sortie ressemble à ceci:

./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
la source
4

Voici comment je gère normalement le formatage comme ça:

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

Je dirige généralement le chat dans un grep pour des informations spécifiques.

MorpheousMarty
la source
3
Faites attention ici. for i in *n'inclura pas de sous-répertoires.
Acumenus
4

Et la solution awk manquante est:

$ awk '(FNR==1){print ">> " FILENAME " <<"}1' *
kvantour
la source
Merci pour votre excellente réponse. Pouvez-vous expliquer le sens de 1la fin de l'expression?
bwangel
1
Merci. Vous pouvez voir quel est le sens de 1 à la fin du script awk
kvantour
3

vous pouvez utiliser cette commande simple au lieu d'utiliser une boucle for,

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

Si vous aimez les couleurs, essayez ceci:

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

ou:

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

ou: (avec le package 'multitail' installé)

multitail *
sjas
la source
1
Par souci de couleurs mettant en évidence le nom de fichier:find . -type f -name "*.txt" | xargs -I {} bash -c "echo $'\e[33;1m'{}$'\e[0m';cat {}"
MediaVince
3

Si tous les fichiers ont le même nom ou peuvent être mis en correspondance find, vous pouvez faire (par exemple):

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

pour trouver, montrer le chemin et cat chaque fichier.

drkvogel
la source
2

Voici un moyen vraiment simple. Vous avez dit que vous vouliez chatter, ce qui implique que vous souhaitiez afficher l'intégralité du fichier. Mais vous devez également imprimer le nom du fichier.

Essaye ça

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

J'espère que cela pourra aider

Trey Brister
la source
4
une syntaxe plus propre serait head -n -0 file.txt file2.txt file3.txt. Fonctionne pour headdans GNU coreutils
doubleDown
1

Cette méthode imprime le nom de fichier puis le contenu du fichier:

tail -f file1.txt file2.txt

Production:

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

==> file2.txt <==
contents of file2.txt ...
contents of file2.txt ...
serenesat
la source
3
Le -fest utile si vous souhaitez suivre un fichier en cours d'écriture, mais pas vraiment dans le cadre de ce que l'OP a demandé.
tripleee
1

Si vous voulez remplacer ces vilains ==> <== par autre chose

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

explication:

tail -n +1 *.txt - sortie tous les fichiers dans le dossier avec en-tête

sed -e 's/==>/\n###/g' -e 's/<==/###/g'- remplacer ==>par une nouvelle ligne + ### et<== juste ###

>> "files.txt" - sortie tout dans un fichier

boroboris
la source
0
find . -type f -exec cat {} \; -print
user5689319
la source
0

Si vous souhaitez que le résultat soit au même format que la sortie souhaitée, vous pouvez essayer:

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

Résultat:

file1
bluemoongoodbeer
file2
awesomepossum
file3
hownowbrowncow

Vous pouvez mettre echo -eavant et après la coupe afin d'avoir également l'espacement entre les lignes:

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

Résultat:

file1

bluemoongoodbeer

file2

awesomepossum

file3

hownowbrowncow
Fekete Sumér
la source
Explication: la forboucle parcourt la liste lsrésultant de la commande. $ ls file{1..3}.txtRésultat: file1.txt file2.txt file3.txtchaque itération sera echola $filechaîne puis elle est canalisée dans une cutcommande où j'ai utilisé .comme séparateur de champ qui divise fileX.txt en deux morceaux et imprime le champ1 (le champ2 est le txt) Le reste doit être clair
Fekete Sumér
0
  • AIX 7.1 ksh

... jetant un coup d'œil à ceux qui ont déjà mentionné les travaux de tête pour certains d'entre nous:

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

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

==> file3.txt <==
zzz
$

Mon besoin est de lire la première ligne; comme indiqué, si vous voulez plus de 10 lignes, vous devrez ajouter des options (tête -9999, etc.).

Désolé d'avoir publié un commentaire dérivé; Je n'ai pas suffisamment d'informations sur la rue pour commenter / ajouter au commentaire de quelqu'un.

JustinKaisse
la source
-1

Pour résoudre ces tâches, j'utilise généralement la commande suivante:

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

C'est un moyen très pratique de concaténer des fichiers si le nombre de fichiers est assez important.

Igor
la source
1
Mais cela ne répond pas à la question du PO.
kvantour
-3

J'ai d'abord créé chaque fichier: echo 'information'> file1.txt pour chaque fichier [123] .txt.

J'ai ensuite imprimé chaque fichier pour m'assurer que les informations étaient correctes: fichier de queue? .Txt

Ensuite, j'ai fait ceci: fichier de queue? .Txt >> Mainfile.txt. Cela a créé le fichier Mainfile.txt pour stocker les informations de chaque fichier dans un fichier principal.

cat Mainfile.txt a confirmé que tout allait bien.

==> file1.txt <== bluemoongoodbeer

==> file2.txt <== awesomepossum

==> file3.txt <== hownowbrowncow

John Ray
la source