• BASH > awk

      GENERALITES

      awk OPTIONS BEGIN { ... } pattern { ... } pattern { ... } END { ... } fichier

      Par défaut, chaque enregistrement est une ligne, chaque champs est séparé par un espace.

      OPTIONS

      awk -F’, change le séparateur de champs par une virgule (,). Si -F"", alors chaque caractère devient un champs.

      VARIABLES INTERNES

      FS : séparateur de champs en entrée

      FS peut être renseigné de deux manières :

       

      awk -F ';' '...' fichier

       

      ou

       

      awk 'BEGIN {FS=";";}'
      

       

      FS peut être de type "simple caractère" ou de type "RegEx" et peut changer à tout instant.

      OFS : séparateur de champs en sortie

      Par défaut, OFS est un espace. La virgule , est le symbole de concaténation. Ainsi, , prendra la valeur de OFS :

       

      awk -F':' '{print $3,$4;}' fichier
      41 41
      100 101
      112 119

       

      awk -F':' 'BEGIN{OFS="=";} {print $3,$4;}' fichier
      41=41
      100=101
      112=119

      RS : séparateur d’enregistremenr (Record Separator)

      Par défaut, RS est le saut de ligne. Exemple avec le fichier fich: Enregistrements séparés par deux \n, et Champs séparés par un \n :

       

      toto
      A
      a
      
      tata
      B
      b

       

      Essayons le script :

       

      awk 'BEGIN { RS="\n\n"; FS="\n"; } { print $1,$2; }' fich
      toto A
      tata B
      titi C

      ORS : Séparateur d’enregistrement en sotie (Output Record Separator)

      Par défaut, ORS est le saut de ligne. Chaque enregistrement sera séparé par un = en sortie :

       

      awk 'BEGIN{ORS="=";} {print;}' fichier
      toto A a=tata B b=titi C c=

      NR : Nombre d’enregistrements (Number of Records)

      Donne le numéro de l’enregistrement. Donc dans END :

       

      awk '{print "record : ",NR;}END {print NR, "records au total";}' fichier
      record :  1
      record :  2
      record :  3
      3 records au total

      NF : Nombre de champs dans un enregistrement (Number of Fields)

      toto A B C D
      tata A B C
      titi A B C D

       

      awk '{print NR,"->",NF}' fich
      1 -> 5
      2 -> 4
      3 -> 5

      FILENAME : Nom du fichier d’entrée courant

      FILENAME renvoie le nom du fichier en cours de traitement.

       

      awk '{print FILENAME}' fichier
      fichier
      fichier
      fichier

      FNR : Nombre d’enregistrements lus dans un fichier

      FNR nombre d’enregistrements lus dans un fichier (remis à zéro à chaque nouveau fichier)

       

      $ awk '{print FILENAME, FNR;}' fich1 fich2
      fich1 1
      fich1 2
      fich1 3
      fich2 1
      fich2 2
      fich2 3

      $0 $1 $2 $3 …

      $0 l’enregistrement entier

      $1 premier champs

      $2 deuxième champs

      $NF le dernier champs de l’enregistrement en cours

      ARGC / ARGV nombre d’arguments / valeur des arguments

      PATTERN

      pattern { } → exécute si pattern renvoie true

       

      /Toto/ si la chaine Toto est trouvée dans l’enregistrement en cours

      !/Toto/ si la chaine Toto n’est pas trouvée dans l’enregistrement en cours

      !(/toto/ || /^tata/) si ne contient pas toto ou ne commence pas par tata

      /foo|bar/ si foo ou bar sont trouvés dans l’enregistrement en cours

      /hel+o/ si he + l (1 ou plus) + o sont trouvés (helo, hello, hellllllo, etc.)

      /to*to/ tto ou toto ou toooooooto

      /t[oi]/ o ou i (t, ti, to)

      $3 > 0 si $3 est strictement plus grand que 0

      $2 >= 5 si $2 est plus grand ou égal à 5

      $2 * $5 > 33 → si $2 multiplié par $5 est plus grand que 33

      $1 == "toto" → si le champs $1 est toto

      $2 >= 4 || $3 <=20 → si

      NF != 3 → si le nombre de champs n’est pas égal à 3

      length($2) > 10 → si $2 a plus de 10 caractères

      $2~/^toto$/ → si $2 contient exactement toto (ni plus ni moins)

      NR==1 , NR==5 → du 1er au 5ème enregistrement

      MANIPULATION DU TEXTE

      Remplacer du texte

      sub( regex , remp , chaine )

       

      Remplace la PREMIÈRE et la plus longue occurrence de regex par remp dans la chaine chaine.

       

      gsub( regex , rep , chaine )

       

      Remplace TOUTES les occurrences. (g pour global).

       

      Exemple : Remplacer tous les # en _ sur le champ $1.

       

      awk '{ gsub(/#/,"_",$1) ; print}' fichier

       

      Pour récupérer la regex (&) :

       

      awk ‘{ sub(/toto/, "& et tata"); print }’→ Remplace le premier toto par toto et tata de chaque ligne.

       

      Autre exemple avec la chaine "daabaaa" :

       

      sub(/a*/, "-&-", str) → d-aa-baa
      gsub(/a*/, "-&-", str) → d-aa-b-aa-

       

      Pour supprimer l’effet du &, il faut le double backslashé : \\&

       

      awk '{ sub(/\|/, "\\&"); print }'

      Couper une chaine

      substr( chaine, début, longueur )
      substr("abcdefghij", 5, 3)
      efg

      NµOTE : La chaine commence à 1.

      Si long est absent : renvoie jusqu’à la fin de la chaine :

       

      substr("abcdefghij", 5) → efghij

      Chercher une chaine

      index( chaine , regex )

       

      Retourne la position de la première occurrence de regex dans chaine.

      note : La chaine commence à 1.

       

      awk ‘BEGIN { print index("foobar", "bar") }’4

       

      Si rien de trouvé, renvoie 0.

       

      match( chaine , regex )

       

      Cherche la plus longue regex dans chaine.

      Retourne la position, sinon retourne 0.

      note : La chaine commence à 1.

       

      awk '{
         endroit = match($0, regex)
         if (endroit)
            print "Trouvé ", regex, " à endroit ", endroit, " dans ", $0
      }' fichier

       

      EXEMPLE : chercher les mots commençant par sa dans la deuxième colonne :

       

      awk '$2 ~ /^sa/' fichier

       

      Pour faire l’inverse : ! avant la tilde ~:

       

      awk '$2 !~ /^sa/' fichier

       

      Plusieurs conditions :

       

      awk '$2 !~ /^sa/ && $1 < 5' favorite_food.txt

       

      ET : && . En fait, si condition1 est TRUE, alors on vérifie condition2.

      Majuscule - Minuscule

      toupper($2)→ capitalise le champs $2

      tolower($2)→ minimalise le champs $2

      Concaténation

      chaine = chaine $1″" → concatène chaine

      Longueur de la chaine

      length($2)

      Présentation du texte

      sprintf(format, expression1,...)

       

      Transforme la présentation du texte comme le ferait printf

       

      sprintf("pi = %.2f (env.)", 22/7)→ pi = 3.14 (env.)

      FONCTIONS

      Tests

      if ( TEST ) blabla else blibli → si TEST renvoie true, alors blabla, sinon blibli

      Calculer le nombre d’enregistrements qui matchent

      /toto/ { total++ }
      END { print total }

      Splitter un champ en tableau

      split( chaine, tableau, motif )

       

      La CHAINE sera divisée en éléments séparés par un MOTIF et envoyés dans un TABLEAU.

       

      Le premier élément du tableau est tableau[1].

       

      MOTIF peut être une RegEx. Si MOTIF est absent, la valeur de FS est utilisée.

       

      split retourne le nombre d’éléments créés.

      RECORD le plus long

      lenghth($0) > total { total = length($0) ; ligne = $0 }
      END { print total, ligne }

      $3 le plus grand

      $3 > max { max = $3 ; ligne = $0 }
      END { print max, ligne }

      Inverser les FIELDS

      { for ( i = NF ; i > 0 ; i++ ) printf("%s", $i) ; printf("\n") }

      Inverser l’ordre des RECORDS

      { ligne[NR] = $0 }
      END {
       i = NR
       while ( i > 0 ){
            print ligne[i]
            i = i - 1
       }
      }

      Somme de tous les FIELDS sauf le 1er

      { somme = 0 ; for ( i = 2 ; i <= NF ; i = i + 1 ) somme = somme + $i ; print somme }

      Compter le nombre de fois qu’une valeur apparaît dans un champ donné

      awk '{ tab[$3]++ }
         END {
            for (i in tab) print i , " est apparu " , tab[i] , " fois."
         }'

       

      tab est le tableau qui va prendre pour indice la valeur du champ $3 (par exemple)

       

      Donc, on incrémente l’élément d’indice de même valeur que le champ.

      Nombre aléatoire

      rand() retourne un nombre entre 0 et 1 (non inclus).

      srand() pour avoir un vrai nombre aléatoire à chaque démarrage du script.

       

      Pour avoir un nombre entier entre 0 et X :

       

      int(X * rand())

      Nombre entier

      int(X) Retourne l’entier de X le plus proche de zéro.

       

      int(3.9)
      3
      int(-3.9)
      -3

      BEGIN et END

      BEGIN : avant que le fichier ne soit analysé - END : après que le fichier soit analysé - BEGIN et END servent à afficher certaines infos :

       

      sudo awk '
      BEGIN { FS=":" ; print "1\t\t2\t\t3\n" ; }
      {print $1,"\t\t",$2,"\t\t",$3;}
      END { print "-FIN-" }
      ' fichier
      1      2   3
      toto   A   a
      tata   B   b
      titi   C   c
      -FIN-

      Envoyer une variable du shell dans awk

      variable="ligne une\nligne deux"
      awk -v var="$variable" 'BEGIN {print var}'
      ligne une
      ligne deux

       

      ———-

      https://www.thegeekstuff.com/tag/awk-tutorial-examples/

      Afficher tout sauf la 1ère colonne :

       

      awk '{$1=""; print $0}' somefile

       

      Afficher tout sauf les deux premières colonnes :

       

      awk '{$1=$2=""; print $0}' somefile

       

      Afficher la deuxième colonne de la dernière ligne :

       

      awk 'END {print $2}'

      QUELQUES LIGNES DE CODES

      awk -F"\t" '$4 != "" && $5 == ""' rain0 | wc -l

       

      awk -F"\t" '$4 != "" && $5 == "" {print $4}' rain0 | sort | uniq -c

       

      awk -F"\t" '$4 == "0.0" && $5 != "" {print $5}' rain0 | sort | uniq -c

       

      awk 'BEGIN {FS=OFS="\t"} $4 == "0.0" && $5 == "" {$5=1} 1' rain0 > rain1

       

      awk -F"\t" '$4 == "" && $5 != "" {print NR": "$0}' rain1

       

      awk -F"\t" '$4 == ""' rain1 | wc -l

       

      awk -F"\t" '$4 == "" {year[$1]++} END {for (i in year) print i"\t"year[i]}' rain1 | pr -t -3
       

       

      awk -F"\t" '$1 >= 1916 && $1 <= 2015' rain1 > rain2

       

      awk -F"\t" '$4 == "" {blanks++; next} $5 > 1 {print blanks,$5} {blanks = 0}' rain2 | sort -n | uniq -c

       

      awk 'BEGIN {FS=OFS="\t"} {$4=""; $5=""} 1' rain2 > dummy

       

      awk -F"\t" '($4 != "0.0" || $6 != "0.0") && $5 == 1 && $7 == 1' four_towns | cut -f4,6  > ulv-bur
      awk -F"\t" '{ulv+=$1; bur+=$2} END {printf ("%s%s%s%0.2f\n", "Burnie factor for ",NR," days is ",ulv/bur)}' ulv-bur

       

      awk -F"\t" 'NR > 1 && $5 >= 1' accums | wc -l
      awk -F"\t" 'NR > 1 && $5 == 2' accums | wc -l

       

      awk 'BEGIN {FS=OFS="\t"} {print $1"-"$2"-"$3,$4}' backfills > BFtrick
      awk 'BEGIN {FS=OFS="\t"} {print $1"-"$2"-"$3,$4,$5,$6,$7,$8,$9,$10,$11}' four_towns > FTtrick

       

      awk 'BEGIN {FS=OFS="\t"} FNR==NR {backfill[$1]=$2; next} $1 in backfill {$2=backfill[$1]; $3="estBF"} 1' BFtrick FTtrick | sed 's/-/\t/g' > four_towns_backfilled

       

      awk -F"\t" 'BEGIN {FS=OFS="\t"} $1 == 1994 && $2 == 11 && $3 == 28 {$4 = "2.0"; $5 = "estIF"} 1' four_towns_backfilled > four_towns_backfilled_infill
      grep -C51994$'\t'11$'\t'28 four_towns_backfilled_infill

       

      awk 'BEGIN {FS=OFS="\t"} $4 == "" {for (i=7;i<=NF;i+=2) if ($i==1) ones++; \
      if ($7 == 1) a=($6*1.02); if ($9 == 1) b=($8*1.02); if ($11 == 1) c=($10*1.21); \
      $4=sprintf("%0.1f",(a+b+c)/ones); $5="estIF"; print; ones=a=b=c=0; next} \
      {print}' four_towns_backfilled_infill > four_towns_backfilled_infilled

       

      AWK here searches for lines with the Ulverstone total field (4) blank. When it finds such a line, it carries out the actions within the first set of curly braces, beginning with "for (1=7)" and ending with "next". That "next" makes AWK move to the next line and start again. If the next line has a non-blank Ulverstone total, the action in the next set of curly braces is carried out, namely "print" the line.

      Back to the first set of actions. First, AWK counts up the number of 1-day totals available, as before, and stores the number in "ones". Next, it checks the Burnie, Latrobe and Northdown period fields (7, 9 and 11). If the period is 1, AWK stores the adjusted total (in fields 6, 8 or 10, multiplied by the appropriate adjustment factors) in a variable ("a" for Burnie, "b" for Latrobe, "c" for Northdown). AWK now replaces the blank field 4 with the average of the available, adjusted 1-day totals at the other stations, printing the average to the nearest 0.1 mm with sprintf. Field 5 (period) is then replaced with "estIF". Note that if "a", "b" or "c" doesn’t exist because there was no 1-day total at that station on that date, then AWK treats the variable as zero in calculating the average. After printing the line, the four variables are all re-set to zero.

      REMPLACER DU TEXTE

      awk '{ a=gensub(/.*#([0-9]+)(\").*/,"\\1","g",$0); if(a~/[0-9]+/) {gsub(/[0-9]+\"/,a+11"\"",$0);}print $0}' fichier

       

      UPDATE

       

      awk 'BEGIN{FS=OFS="\" \"#"}{if(NF<2){print;next;}
              a=gensub(/.* ([0-9]+)$/,"\\1","g",$1);
              b=gensub(/([0-9]+)\"/,"\\1","g",$2);
              gsub(/[0-9]+$/,a+11,$1);
              gsub(/^[0-9]+/,b+11,$2);
              print $1,$2
      }' yourFile

       

      gensub(regexp, replacement, how [, target]) #
          Search the target string target for matches of the regular expression regexp.
          If "how" is a string beginning with ‘g’ or ‘G’ (short for “global”), then
              replace all matches of regexp with replacement.

      récupérerune expression

      awk '{ r = gensub(/a(b*)c/, "Blabla: \\1", "g"); print r; }'

      COMMANDES SYSTEMES ET VARIABLES

      awk '{system("wc "$1)}' myfile

      ECRIRE DIRECTEMENT DANS UN FICHIER

      A la manière de sed -i :

      gawk -i inplace '{ gsub(/foo/, "bar") }; { print }' fichier

       

      Pour créer une archive :

      gawk -i inplace -v INPLACE_SUFFIX=.bak '{ gsub(/foo/, "bar") } { print }' fichier

       

 

Aucun commentaire

 

Laissez un commentaire