2017-08-15 5 views
1

J'ai quelques fichiers CSV que je voudrais analyser avec grep (ou une autre fonction du terminal) afin d'extraire quelques informations. Ils sont sous cette forme:Comment ajouter une valeur à la fin de chaque ligne obtenue avec grep

* Comment 1 
* Comment line 2 explaining what the following numbers mean 
1000000 ; 3208105 ; 0.18 ; 0.45 ; 0.00015 ; 0.1485 ; 0.03 ; 1 ; 1 ; 5 ; 477003 ; 

* Comment 3 
* Comment 4 explaining the meaning of the following lines 

* Comment 5 
0; 706520; p; 30.4983 
1; 20859; p; 57.8 
2; 192814; p; 111.842 
3; 344542; p; 130.543 
4; 54605; p; 131.598 
5; 64746; d; 140.898 
6; 442082; p; 214.11 
7; 546701; p; 249.167 
8; 298394; p; 305.034 
9; 81188; p; 305.034 
....... 

Dans chaque fichier il pourrait y avoir au plus une ligne dans laquelle le troisième champ est égal à d au lieu de p. Donc, soit il y a une ligne contenant un d ou il n'y en a pas.

J'ai beaucoup de fichiers comme ceci et ce que je voudrais faire est d'extraire de chaque fichier la ligne (si présente) contenant la lettre d et d'ajouter après cette ligne le dernier paramètre de la première ligne sans commentaire, que dans cet exemple serait 47703. Jusqu'à présent, j'ai réussi à extraire séparément les lignes dont j'avais besoin.

Avec cela, je peux extraire toutes les lignes contenant un d de chaque fichier que j'ai:

grep -h -E ' d;' *.csv > output.csv 

Et avec cela, je peux extraire précisément le nombre 47703 d'un fichier comme celui dans l'exemple:

grep -v -e "^*" -e " p; " -e " d; " example_file.csv | cut -d \; -f 11 

Mais je ne sais pas comment mettre ces deux ensemble.

La sortie finale, je voudrais obtenir de l'exemple au début est une seule ligne comme celui-ci:

5; 64746; d; 140.898; 47703 

et je voudrais avoir une ligne comme celui-ci pour chaque fichier CSV dans le répertoire courant .

Existe-t-il un moyen de le faire?

+0

S'il vous plaît ajouter l'entrée de l'échantillon et votre sortie désirée pour cette entrée de l'échantillon à votre question. – Cyrus

+0

J'ai fait. L'entrée est le premier exemple et la sortie est la dernière ligne – jackscorrow

Répondre

1

je boucle en boucle tous les fichiers .csv et attribuer des valeurs renvoyées par vos greps à des variables, qui sont concaténées à la fin de chaque boucle écho:

for f in *.csv ; do value=`grep -v -e "^*" -e " p; " -e " d; " -e '^\s*$' "$f" | cut -d \; -f 11` ; line=`grep -h -E ' d;' "$f" ; echo "$line;$value" ; done

Edit: (J'ai aussi ajouté -e '^\s*$' au premier grep, qui obtient la ligne avec des valeurs sur la première ligne non commentée.Avant, il a correspondu aux lignes vides)

cela fait seulement écho des lignes comme 5; 64746; d; 140.898; 47703, que vous vouliez. Si vous souhaitez rediriger vers un certain fichier (toutes les lignes trouvées seront dans le fichier de sortie unique), vous pouvez l'ajouter au dernier écho dans cette commande à long, comme:

for f in *.csv ; do value=`grep -v -e "^*" -e " p; " -e " d; " -e '^\s*$' "$f" | cut -d \; -f 11` ; line=`grep -h -E ' d;' "$f" ; echo "$line;$value" > output.csv ; done

pour une meilleure lisibilité, même code sur plusieurs lignes:

for f in *.csv 
do 
    value=`grep -v -e "^*" -e " p; " -e " d; " -e '^\s*$' "$f" | cut -d \; -f 11` 
    line=`grep -h -E ' d;' "$f" 
    echo "$line;$value" 
done 
2

Cela ressemble à un travail pour sed:

parse.sed (GNU sed)

/^ +$/d       # Ignore empty lines 
/^[ 0-9;.]+$/h     # Save first "number-only" line to hold space 
/d;/{       # Run block on lines containing ' d; ' 
    G        # Copy saved line to pattern space 
    s/\n.*; ([0-9]+) *; *$/; \1/ # Append the last number on the second line 
    p        # to the first line and print the result 
} 

analyse.sed (portable sed)

# Ignore empty lines 
/^ +$/d       

# Save first "number-only" line to hold space 
/^[ 0-9;.]+$/h     

# Run block on lines containing ' d; ' 
/d;/{       

    # Copy saved line to pattern space 
    G        

    # Append the last number on the second line 
    # to the first line and print the result 
    s/\n.*; ([0-9]+) *; *$/; \1/ 
    p        
} 

Exécuter comme ceci:

sed -Enf parse.sed infile.csv 

Sortie:

5; 64746; d; 140.898; 477003 

Notez que ceci suppose que avez une ligne contenant le groupe de caractères [ 0-9;.] dans la fichier.

Pour exécuter sur tous les fichiers csv locaux, procédez comme suit:

sed -Enf parse.sed *.csv 
+0

Lorsque j'essaie d'exécuter ce fichier dans un seul fichier, il me donne l'erreur 'sed: 1: parse.sed: caractères supplémentaires à la fin de la commande d – jackscorrow

+0

@jackscorrow : Désolé, je n'ai pas testé le script dans BSD sed. Voir la version portable ajoutée – Thor

+0

Ok, maintenant ça marche. Merci! Dès que je peux je vais essayer votre solution et voir laquelle est la meilleure – jackscorrow