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

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

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.


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.


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.


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

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

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.


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

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.


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


3

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

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

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 *

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.


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


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

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



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

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.


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


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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.