Comment imprimer les valeurs d'un fichier texte dans un fichier en colonnes à l'aide d'un script shell

11

J'ai un output.txt de l'exécution d'un script shell comme suit:

abc.txt
errorstatus1
Fri Nov 11 02:00:09 2016
def.txt
errorstatus2.txt
Sat Nov 12 03:00:09 2016

Le fichier texte comporte plusieurs entrées ligne par ligne de la même manière. Je souhaite imprimer ces valeurs dans des colonnes: nom de fichier, statut et horodatage comme suit:

Filename      Status        Timestamp
abc.txt     errorstatus1   Fri Nov 11 02:00:09 2016
def.txt     errorstatus2   Sat Nov 12 03:00:09 2016
linux09
la source
4
Le format d'exemple n'est pas un fichier CSV, c'est un fichier à largeur de colonne fixe. Vous voudrez peut-être clarifier la question ou fournir un exemple correct.
AlexP
Votre exemple n'est pas un format CVS. Le format CVS est abc.txt,errorstatus1,Fri Nov 11 02:00:09 2016. J'ai modifié votre question pour qu'elle corresponde à ce qu'elle dit avec l'exemple que vous avez fourni. N'hésitez pas à revenir en arrière, mais veuillez noter que vous devez vraiment clarifier ce que vous voulez exactement - valeurs en colonnes ou valeurs séparées par des virgules
Sergiy Kolodyazhnyy

Réponses:

14

Avec paste:

paste - - - <file.txt

cela produira le contenu du fichier séparé par des sauts de ligne sous forme de colonnes et trois colonnes séparées par des tabulations par ligne.

Ajout de l'en-tête:

echo Filename Status Timestamp; paste - - - <file.txt

Pour classer la sortie en colonnes, prenez l'aide de column:

{ echo Filename Status Timestamp; paste - - - <file.txt ;} | column -t

Exemple:

% cat file.txt
abc.txt
errorstatus1
Fri Nov 11 02:00:09 2016
def.txt
errorstatus2.txt
Sat Nov 12 03:00:09 2016

% { echo Filename Status Timestamp; paste - - - <file.txt ;} | column -t
Filename  Status            Timestamp
abc.txt   errorstatus1      Fri        Nov  11  02:00:09  2016
def.txt   errorstatus2.txt  Sat        Nov  12  03:00:09  2016
heemayl
la source
Cool! Merci!! Mais comment imprimer ces valeurs au format Excel. Je veux les en-têtes de colonne dans la feuille Excel en tant que statut de nom de fichier et horodatage et les valeurs en dessous
linux09
@ linux09 Créez un CSV et importez avec Excel:echo Filename,Status,Timestamp; paste -d ',' - - - <file.txt
heemayl
Brillant! Fonctionne comme un charme. Merci beaucoup
linux09
6

Vous pouvez utiliser awk:

awk 'NR % 3 {printf "%s ", $0; next}1'

La sortie pourrait ne pas être aussi jolie:

$ awk 'NR % 3 {printf "%s ", $0; next} 1' input
abc.txt errorstatus1 Fri Nov 11 02:00:09 2016
def.txt errorstatus2.txt Sat Nov 12 03:00:09 2016

Vous pouvez utiliser à la %s\tplace une sortie séparée par des tabulations.

  • NR % 3est zéro (et faux) pour chaque troisième ligne, donc les autres lignes sont imprimées avec un espace après elles au lieu d'une nouvelle ligne. nextcommence juste la prochaine itération.
  • Chaque troisième ligne est imprimée telle 1quelle à cause de la finale , avec une nouvelle ligne après, car elle ne correspond pas au premier bloc.
muru
la source
5

Il y a aussi rs(l' utilitaire hape BSD r e s ):

DESCRIPTION
     rs reads the standard input, interpreting each line as a row of blank-
     separated entries in an array, transforms the array according to the
     options, and writes it on the standard output.  With no arguments it
     transforms stream input into a columnar format convenient for terminal
     viewing.

En particulier,

     -e      Consider each line of input as an array entry.

Donc

$ rs -e < file
abc.txt                   errorstatus1              Fri Nov 11 02:00:09 2016
def.txt                   errorstatus2.txt          Sat Nov 12 03:00:09 2016

ou (pour ajouter l'en-tête)

$ { printf '%s\n' Filename Status Timestamp ; cat file ; } | rs -e
Filename                  Status                    Timestamp
abc.txt                   errorstatus1              Fri Nov 11 02:00:09 2016
def.txt                   errorstatus2.txt          Sat Nov 12 03:00:09 2016
tournevis
la source
3

Pour être complet, vous pouvez aussi le faire avec sed:

sed -e '1iFilename\tStatus\tTimestamp' -e 'N;N;y/\n/\t/' file.txt
  • 1iFilename\tStatus\tTimestamp insère la ligne d'en-tête avant la ligne 1
  • N;N lit deux lignes supplémentaires dans le tampon de motif, ce qui donne un total de 3 lignes séparées par une nouvelle ligne
  • y/\n/\t/ remplace toutes les nouvelles lignes par des tabulations dans le tampon de motif

Les i, Net les ycommandes sed sont documentées ici .

Traumatisme numérique
la source
Très bien. Pourriez-vous également commenter brièvement les expressions que vous avez utilisées? Merci!
Campa
oui, mec parfait
Campa
1

Il est toujours possible de préparer quelque chose pour le traitement de texte avec AWK ou Perl, et bien sûr Python, ce que fournit cette réponse.

En une ligne:

python -c 'import sys;print "Filename\tStatus\tTimestamp"; lines=[l.strip() for l in sys.stdin];print "".join([l+"\n" if i%3 == 0 else l+"\t" for i,l in enumerate(lines,1) ])' < input.txt

En tant que script multiligne

import sys
print "Filename\tStatus\tTimestamp"
lines=[l.strip() for l in sys.stdin]
print "".join([l+"\n" if i%3 == 0 else l+"\t" for i,l in enumerate(lines,1) ])

L'idée de base ici est de donner l'entrée de script via stdin (en utilisant la redirection du shell <, bien qu'un tube puisse également être utilisé). Le script utilise des tabulations pour séparer les champs, bien que des espaces puissent également être utilisés pour une sortie plus "affinée".

Exemple de sortie à l'aide d'un exemple d'entrée fourni par OP:

$ python -c 'import sys;print "Filename\tStatus\tTimestamp";                                   
> lines=[l.strip() for l in sys.stdin];
> print "".join([l+"\n" if i%3 == 0 else l+"\t" for i,l in enumerate(lines,1) ])' < input.txt
Filename    Status  Timestamp
abc.txt errorstatus1    Fri Nov 11 02:00:09 2016
def.txt errorstatus2    Sat Nov 12 03:00:09 2016
Sergiy Kolodyazhnyy
la source