Ajout d'une colonne de valeurs dans un fichier délimité par des tabulations

17

Comment puis-je ajouter une colonne de valeurs dans un fichier qui a un certain nombre de lignes. J'ai un fichier d'entrée comme celui-ci:

Fichier d'entrée:

SPATA17 1   217947738
LYPLAL1 1   219383905
FAM47E  4   77192838
SHROOM3 4   77660162
SHROOM3 4   77660731
SHROOM3 4   77662248

Fichier de sortie:

SPATA17 1   217947738 file1
LYPLAL1 1   219383905 file1
FAM47E  4   77192838  file1
SHROOM3 4   77660162  file1
SHROOM3 4   77660731  file1
SHROOM3 4   77662248  file1

Dans ce cas, je veux ajouter une colonne de valeurs, jusqu'au nombre de lignes dans le fichier. La valeur reste cohérente, comme "file1".

La raison en est que j'ai 100 de ces fichiers. Je ne veux pas ouvrir chaque fichier et coller une colonne. Il existe également un moyen d'automatiser cela, en allant dans un répertoire et en ajoutant une colonne de valeurs. La valeur provient du nom de fichier, qui doit être ajouté dans chaque ligne du fichier dans la dernière / première colonne.

Ron
la source

Réponses:

22

Vous pouvez utiliser une boucle à une ligne comme celle-ci:

for f in file1 file2 file3; do sed -i "s/$/\t$f/" $f; done

Pour chaque fichier de la liste, cela servira sedà ajouter à la fin de chaque ligne un onglet et le nom du fichier.

Explication:

  • Utilisation de l' -iindicateur avec sedpour effectuer un remplacement sur place, écrasement du fichier
  • Effectuez une substitution avec s/PATTERN/REPLACEMENT/. Dans cet exemple, le MOTIF est $, la fin de la ligne, et REMPLACEMENT est \t(= un TAB), et $fest le nom de fichier, de la variable de boucle. La s///commande est entre guillemets doubles afin que le shell puisse développer des variables.
janos
la source
Le code fonctionne. Pouvez-vous expliquer le contenu entre guillemets?
Ron
Tout comme "awk" est utilisé lorsque vous travaillez avec des colonnes, "sed" est également utilisé pour des situations similaires. Je suis novice pour "awk" et "sed".
Ron
@Ron sedest le plus pratique pour la substitution de modèles et l'enregistrement sur place. Pour votre besoin d'enregistrer le fichier, c'était une option relativement pratique. Si vous n'avez pas besoin de réécrire dans le même fichier que vous traitez, il awkest généralement beaucoup plus facile de travailler avec.
janos
Personnellement, je suis awktrop souvent gêné par les séparateurs de champs d'entrée / sortie, et j'essaie donc d'éviter de l'utiliser autant que possible, ce qui rend sedplus attrayant.
user5359531
11

Venez pourquoi vous recommandez ces outils puissants quand il y a pastecommande!

$ cat a
A
B
C
D
$ cat b
1
2
3
4
$ paste a b
A   1
B   2
C   3
D   4

Avec une petite ruse, vous pouvez utiliser pastepour le but de l'OP. Cependant, il ne remplacera pas les fichiers en place:

for f in file1 file2 file3; do 
    paste $f <(yes $f | head -n $(cat $f | wc -l)) > $f.new
done

Cela va coller le nom de fichier respectif comme dernière colonne de chaque fichier dans un nouveau fichier filename.new

yegle
la source
Merci! pasteest sûrement un joyau caché.
neu242
10

Vous pouvez utiliser awk:

awk '{print $0, FILENAME}' file1 file2 file3 ...
cuonglm
la source
Étant donné que chaque fichier a un nom différent, je dois le faire 100 fois. Y a-t-il un moyen de le faire une fois?
Ron
Non, FILENAMEest une variable dans awk, elle se développe jusqu'au nom de fichier en cours de awktraitement. Vous n'avez qu'à le faire, alimenter tous les fichiers awk.
cuonglm
ok, mais comment diriger la sortie dans un nouveau fichier, de chaque fichier? awk stocke-t-il chaque fichier pendant le traitement?
Ron
Si vous avez GNU awk 4.1.0ou plus tard, vous pouvez utiliser -ipour éditer sur place. Sinon, vous devez rediriger la awksortie vers un fichier temporaire, puis utiliser greppour extraire la ligne de chaque fichier.
cuonglm
Eh bien, vous pouvez le fairefor file in *; do awk 'BEGIN{OFS="\t"}{print $0, FILENAME}' $file; done
fedorqui