1
votes

Bash: Comment ajouter un préfixe à une ligne lorsqu'un numéro spécifique correspond à une ligne

J'ai un problème simple auquel je n'arrive pas à trouver une solution appropriée. J'ai une ligne avec de nombreuses lignes comme celle-ci:

cat test.csv | awk -F ';' '{print $1,$2,$3,$4,$5,$6}' | awk '{if($3 == 954) print "1;"$0;}'

Je veux ajouter un préfixe 1; à toutes les lignes où le 3ème champ correspond à 954 , donc ça finit comme ça:

1;2020-10-07;2020-07-17;954;7004;something;something
2020-10-14;2020-07-16;955;10038;something;something

J'ai une très mauvaise façon de faire ça maintenant avec:

2020-10-07;2020-07-17;954;7004;something;something
2020-10-14;2020-07-16;955;10038;something;something


0 commentaires

3 Réponses :


2
votes

Awk peut faire votre travail facilement

awk 'BEGIN{
         FS=OFS=";"       # set input and output field separator
     }
     $3 == 954{           # if 3rd field equal to 954 then
         print 1,$0;      # print 1 and then existing record/row
         next             # go to next line
     }1                   
     ' 

Avec vos fichiers d'entrée:

$ cat file
2020-10-07;2020-07-17;954;7004;something;something 
2020-10-14;2020-07-16;955;10038;something;something

$ awk 'BEGIN{FS=OFS=";"}$3 == 954{print 1,$0;next}1' file
1;2020-10-07;2020-07-17;954;7004;something;something 
2020-10-14;2020-07-16;955;10038;something;something

$ awk 'BEGIN{FS=OFS=";"}$3 == 954{$0=1 OFS $0}1' file
1;2020-10-07;2020-07-17;954;7004;something;something 
2020-10-14;2020-07-16;955;10038;something;something

$ awk 'BEGIN{FS=OFS=";"}{print ($3==954 ? 1 OFS:"") $0}' file
1;2020-10-07;2020-07-17;954;7004;something;something 
2020-10-14;2020-07-16;955;10038;something;something

Explication

awk 'BEGIN{FS=OFS=";"}$3 == 954{print 1,$0;next}1' file

#OR

awk 'BEGIN{FS=OFS=";"}$3 == 954{$0=1 OFS $0}1' file

#OR

awk 'BEGIN{FS=OFS=";"}{print ($3==954 ? 1 OFS:"") $0}' file
  • $ 3 == 954 {$ 0 = 1 OFS $ 0} 1 : si le 3ème champ est égal à 954, modifiez l'enregistrement / la ligne existante ( $ 0 ), avec value 1 , séparateur de champ de sortie OFS puis ligne / enregistrement existant ( $ 0 ).

  • Donc à la fin } 1 : Le 1 à la fin de votre script est une condition (toujours vraie) sans action, donc il exécute l'action par défaut pour chaque ligne, imprimant la ligne (qui peut avoir été modifiée par l'action précédente entre accolades)


2 commentaires

Merci beaucoup, cela a parfaitement fonctionné pour moi et j'apprécie vraiment l'explication! :)


Heureux de savoir que cela a aidé. Vous pouvez accepter la réponse si vous pensez qu'elle est résolue



0
votes

Ce one-liner peut également aider:

awk -F';' '{p=$3==954?"1;":""}{print p$0}' file 

La raison pour laquelle vous avez perdu le ; dans la sortie:

Si vous écrivez print $ 1, $ 2 ... awk utilisera le OFS par défaut qui est un espace. Pour résoudre le problème, vous avez essentiellement deux façons de procéder:

  1. définir OFS c'est simple, comme le montre l'autre réponse
  2. ne définissez aucun champ, par exemple ne faites pas quelque chose comme $ 2 = ... , utilisez plutôt sub () , gsub () pour changer le texte. Lorsque vous imprimez, n'incluez pas de virgule , , imprimez simplement $ 0 en concaténant d'autres chaînes. (mon one-liners montre de cette façon)


0 commentaires

0
votes

Avec sed , macthing la 3ème colonne devrait être bien, mais s'il y a plus de 5 colonnes, alors awk est le chemin.

sed '/\([^;]*\)\([^;]*\);954[^;]*\(.*\)/s/^/1;/' file.txt 


0 commentaires