• du code du code du code

      il pleut bergère

      Un fichier rain3 avec les précipitations quotidiennes du 1er janvier 1916 au 31 décembre 2015 :

       

      head -n4 rain3
      Year     Month    Day    UlvT    UlvP
      1916     01       01     0.0     1
      1916     01       02     0.0     1
      1916     01       03     0.0     1
      
      tail -n3 rain3
      2015     12       29     0.0     1
      2015     12       30     0.0     1
      2015     12       31     0.0     1 

       

      Quel est le jour le plus pluvieux :

       

      tail -n +2 rain3 | awk -F"\t" '$4 > biggie {biggie = $4;} END {print biggie}'
      150.6

       

      tail affiche tout à partir de la ligne 2

       

      NOTE : on n’a pas besoin d’initialiser une variable avec awk. Si l’on veut initialiser, il faut le faire dans BEGIN :

       

      awk -F"\t" 'BEGIN {biggie = 0} $4 > biggie {biggie = $4; } END {print biggie}'

       

      Pour forcer une chaine de caractère à être reconnue comme un nombre, il faut ajouter 0 derrière : $var+0

       

      AWK : traiter la première puis passer à la suivante

       

      awk 'NR==1 {tot = $4+0; next} $4 > tot {tot = $4;} END {print tot}' fichier

       

      Combien de jours y-a-t-il eu avec plus de X mm de précipitation :

       

      tail -n +2 rain3 | awk 'BEGIN {print "Min_mm\tNo_days"} {for (i=0;i<=100;i+=5) if ($4 >= i) s[i]++} \
      END {for (a in s) {print a"\t"s[a]}}'
      Min_mm No_days
      0      36525
      5      5759
      10     3106
      15     1867
      20     1098
      25     662
      30     408
      35     258
      40     157
      45     106
      50     62
      55     48
      60     38
      65     26
      70     14
      75     10
      80     8
      85     7
      90     4
      95     3
      100    3

       

      AWK first prints a couple of column headers: "Min_mm" for the minimum rainfall and "No_days" for the number of days with that minimum rainfall.

      La boucle for commence avec i=0 (0 mm) pour finir à 100, incrémentée de 5.

      Pour chaque i, AWK checks to see if field 4′s value is greater than or equal to "i". If it is, AWK adds a count of 1 to an array "s" with index "i". After going line by line through the 36525 totals, AWK goes through the arrays and for each one prints the index value, a tab character, and the count of days.

       

       

      grep -C3 "150.6" rain3
      1929   04   02   0.0     1
      1929   04   03   1.5     1
      1929   04   04   85.1    1
      1929   04   05   150.6   1
      1929   04   01   29.2    1
      1929   04   01   0.0     1
      1929   04   01   13.5    1

       

      Quelles sont les chances pour qu’il pleuve le lendemain d’un jour pluvieux ?

      Quelles sont les chances pour qu’il ne pleuve pas le lendemain d’un jour pluvieux ?

       

      Voici une liste avec une succession de F (fine) et R (rain) :

       

      cat fichier
      F
      F
      R
      F
      R
      R
      F
      R
      R
      F

       

      Puis, convertir les retour-chariot en espace séparateur :

       

      paste -s -d" " fichier
      F F R F R R F R R F

       

      Puis la loupe :

       

      awk '{for (i=2;i<=10;i++) \
      if ($i=="F" && $(i-1)=="F") FF++; \
      else if ($i=="F" && $(i-1)=="R") FR++; \
      else if ($i=="R" && $(i-1)=="F") RF++; \
      else RR++} \
      END {print "fine > fine = "FF"\nfine > rain = "FR"\nrain > fine = "RF"\nrain > rain = "RR}'
      fine > fine = 1
      fine > rain = 3
      rain > fine = 3
      rain > rain = 2

       

      For each of the 9 fields starting with field 2, AWK checks the "F" or "R" value and increments an appropriate variable. For example, if the field has "F" and the preceding field has "F", the "FF" variable is incremented. At the end, prints out the 4 variables after a text "explainer.

       

      De retour au fichier rain3 , or rather the 4th field minus its header line, which is a list of 36525 daily rainfall totals. How do I convert that list of numbers to "F" and "R" values before feeding it to paste and AWK? Qu’es-ce qu’une journée pluvieuse ? Disons à partir de 0.2 mm :

       

      echo -e "0.0\n0.3\n0.2\n0.1"
      0.0
      0.3
      0.2
      0.1
      
      echo -e "0.0\n0.3\n0.2\n0.1" > awk '{ if ($1 <= 0.1 ) $1 = "F" ; else $1 = "R" ; print } '
      F
      R
      R
      F

       

      Having converted the 36525 falls to "F" and "R", I can feed that list to paste and the big AWK command:

       

      cut -f4 rain3 | tail -n +2 | awk '{ if ($1 <= 0.1 ) $1 = "F" ; else $1 = "R" ; print } ' | paste -s -d' ' | \
      awk '{for (i=2;i<=10;i++) \
      if ($i=="F" && $(i-1)=="F") FF++; \
      else if ($i=="F" && $(i-1)=="R") FR++; \
      else if ($i=="R" && $(i-1)=="F") RF++; \
      else RR++} \
      END {print "fine > fine = "FF"\nfine > rain = "FR"\nrain > fine = "RF"\nrain > rain = "RR}'
      fine > fine = 16031
      fine > rain = 5989
      rain > fine = 5989
      rain > rain = 8515

       

      Pourcentages :

      fine > fine : 16031/(16031+5989) = 73%

      rain > rain : 8515/(58515+5989) = 59%

       

      (16031+8515)/36524, or 67% likely to be the same as today’s, soit  2 chances sur 3.

      I’ll remember that as a rule of thumb, since I’ll probably forget the 73% and 59%!

       

      ———

      Shifty dates

      One is to paste together the original table (demo, shown above) and the result of cutting out the date field and processing it with date to convert ISO8601 dates to UNIX seconds, as shown below. The -f option for date tells the command to work line by line through the indicated file.

       

      paste demo <(date -f <(cut -f3 demo) +%s) > demoA

       

      The second method uses AWK and looks more complicated, but it’s considerably faster on large files:

       

      awk -F"\t" '{split($3,t,"-"); print $0 FS mktime(t[1]" " t[2]" "t[3]" 0 0 0")}' demo > demoA

       

      Like date -d [date] +%s, "mktime" on a Linux system will convert a date into UNIX seconds. What goes into the parentheses after "mktime" is YYYY MM DD HH MM SS. To get YYYY MM DD from the hyphenated YYYY-MM-DD in field 3 of demo, I use another AWK built-in, "split". Here "split" takes field 3, splits it into the 3 bits separated by hyphens, and puts each of the bits into an array "t". The elements of the array can be called up later: t[1] is YYYY, t[2] is MM and t[3] is DD.

      After splitting field 3, AWK’s next job is to print. First it prints the whole line ($0), then the field separator FS (a tab in this table), then the UNIX seconds as calculated by "mktime". When AWK moves to the next line, the "split" command starts afresh and array "t" gets the pieces from the current line.

       

      If there are two records in the table differing only in date (by 1462 days, and of course also by the unique ID number), then the "end date" member of the pair can be found with a trick. First I’ll pull out of demoA a sorted, uniquified list of recorder, latitude, longitude, species and UNIX time:

       

      cut -f2,4,5,6,7 demoA | sort | uniq > demoB

       

      Next, I’ll add 126316800 seconds to the UNIX time in all the records. That’s 1462 days times 86400 seconds per day. If an abbreviated record with added seconds is the same as one of the original records, that’s the "end date" version of an existing "start date" record. I can find these with the comm -12 command, which prints lines common to the two files being compared:

       

      comm -12 <(sort demoB) <(awk 'BEGIN {FS=OFS="\t"} {print $1,$2,$3,$4,$5+126316800}' demoB | sort) > demoC

       

      The "start date" versions of these "end date" records will have 126316800 fewer seconds in their UNIX time field. If I concatenate these "start date" and "end date" versions, I get a list of Excel duplicate pairs, but without the unique ID for the record:

       

      cat demoC <(awk 'BEGIN {FS=OFS="\t"} {print $1,$2,$3,$4,$5-126316800}' demoC) > demoD

       

      Now to find those shifted-date pairs in demoA and present them as they looked in the original records, with their unique ID number restored. The most straightforward way would be to search demoA with grep -f, where the "-f" option tells grep to use the contents of a file, in this case demoD, as its search pattern. Unfortunately grep doesn’t like the tab characters that separate the fields in demoD. I’ll therefore modify demoD with AWK to make it more grep-friendly:

       

      awk 'BEGIN {FS="\t";OFS="[[:space:]]"} {$1=$1} 1' demoD

       

      This command replaces tab characters as field separators (FS) with the string "[[:space:]]", which is a POSIX class character that grep understands as whitespace or tab. The "$1=$1″ bit forces AWK to reset the field separators, and the trailing "1″ tells AWK to process every line.

       

      Not quite ready, because in demoA there’s that ISO8601 date string between the recorder field and the latitude field. No problem for AWK, I’ll just prefix field 2 (the latitude field) with a string representing some unknown characters (the ISO8601 string) plus that "[[:space:]]" string:

       

      awk 'BEGIN {FS="\t";OFS="[[:space:]]"} {$2=".*[[:space:]]"$2} 1' demoD > demoE

       

      demoE is now the file containing the parts-of-lines that I want grep to find in demoA. I’ll take what it finds, sort the result, cut off those appended UNIX seconds and sed a space between pairs of lines:

       

      grep -f demoE demoA | sort -t $'\t' -k2 | cut -f7 --complement | sed n\;G

       

      And there they are: the 2 possible Excel date duplicate pairs, separated within a pair by 4 years and a day, and neatly presented.

      ———

      File manager: open a terminal, but not here

      Thunar et Xfe allows me to open a terminal in a selected directory. In Thunar, I right-click on a directory and choose Open Terminal Here, and in Xfe I use the keyboard shortcut Ctrl + t.

       

      installer wmctrl. It’s a handy little utility that can control what workspace you’re on and what’s in a given workspace.

      wmctrl specifies workspaces by number, starting with 0. For example, if I have 3 workspaces on my desktop, the first one is "0″, the second is "1″ and the third is "2″. my file manager is always open in workspace 2. If I do the "open terminal here" thing, I want that terminal to open in workspace 3, next door, which wmctrl knows as "2″.

       

      pour lancer un terminal dans XFCE :

       

      xfce4-terminal --geometry=125x45+70+80

       

      --geometry=largeurxhauteur+posH+posV

       

      dans un fichier termshift, and put it in my scripts folder, where I made it executable:

       

      #!/bin/bash
      wmctrl -s 2; wmctrl -R <(xfce4-terminal --geometry=125x45+70+80)

       

      wmctrl -s 2 moves me to workspace 3 on my desktop.

      wmctrl -R launches my terminal in that workspace and raises its focus.

      Thunar

      Edit > Configure custom actions… Here the example given by the Thunar developers is "Open Terminal Here". I selected this example and opened its edit dialog. In the Command section, I replaced the default terminal command with the path to my termshift script. No command parameters (with "%") are necessary after the path, and I left the file pattern as "*" in the Appearance Conditions tab.

      When I now right-click on a directory in the tree in Thunar’s left-hand pane and choose "Open Terminal Here", I’m moved from workspace 2 to workspace 3 and into an Xfce terminal whose working directory is the one I selected in Thunar.

      Xfe

      simply copied the script to my /home/bob/.config/xfe/scripts/ folder. To do the "open terminal but on a different workspace" trick, I now right-click on a selected directory either in Xfe’s left-hand directory pane, or on any item within that directory in the right-hand pane. On the right-click menu I select Scripts, and termshift appears to the right of that word in a sub-menu. Clicking on termshift runs the script.

       

      ———

      Sorting numbers inside text strings

      I have a script that compiles and sorts museum collection data. One of the data fields is for museum registration codes, and a plain sort doesn’t understand that humans expect "KS.99″, for example, to come before "KS.100″:
      echo -e "KS.99|nKS.100"
      KS.99
      KS.100
      echo -e "KS.99|nKS.100" | sort
      KS.100
      KS.99

       

      My script instead uses the magic "-V" option for GNU sort, and gets the human-friendly result:

       

      echo -e "KS.99|nKS.100" | sort -V
      KS.99
      KS.100

       

      V is short for "version" (the long option is "--version"). As it says in the GNU coreutils manual, the purpose is to sort by version name and number, lowest first.

      It behaves like a default sort, except that each sequence of decimal digits is treated numerically as an index/version number.

       

      -V also works if the numbers are in the middle of a string.and it gives the order that humans would expect even when there are numbers embedded in several places in the string: You can also use sort -V on particular fields in a sort:

       

      echo -e "a3\tb10\na4\tb9"
      a3      b10
      a4      b9
      
      echo -e "a3\tb10\na4\tb9" | sort -t$'\t' -Vk2,2
      a4      b9
      a3      b10

       

      LES LIMITES : The GNU developers warn that version-sorting looks for strings built like this:

       

      prefix[number]suffix

       

      where "suffix" matches the regular expression

       

      (\.[A-Za-z~][A-Za-z0-9~]*)*

       

      and that some strings may not sort as expected. I haven’t had a problem with my museum registration codes, though, even for "sub-sample" codes :

       

      echo -e "KS.100\nKS.100.9\nKS.100.9.1" | shuf
      KS.100.9.1
      KS.100
      KS.100.9
      
      echo -e "KS.100\nKS.100.9\nKS.100.9.1" | shuf | sort -V
      KS.100
      KS.100.9
      KS.100.9.1 

       

      Another warning is that non-numeric "prefix" strings are sorted using C-style collation, with uppercase letters before lowercase. This could indeed be a problem:

      ———

       

      Les flags dans AWK

      Flags in AWK are variables which are set to either true or false. They’re handy for defining ranges over which AWK can act, as shown below.

      I’ll demonstrate with a simple text file called demo, which has 6 lines with 3 comma-separated letters on each line:

       

      a,b,c
      b,d,b
      c,j,k
      x,e,d
      s,r,x
      m,n,o

       

      Print the line with ‘j’ as second letter :

       

      awk -F, '$2=="j"' demo
      c,j,k

       

      Print all lines up to but not including the line with ‘j’ as second letter

       

      awk -F, '$2=="j" {exit} 1' demo
      a,b,c
      b,d,b

       

      When the pattern $2=="j" is matched, the program exits. The ’1′ at the end of this command tells AWK to print every line it processes. It’s AWK shorthand for if 1 is true, print the line, and ’1′ is always true (1 always equals 1). You could use ’42′ (42 always equals 42) or some other number and get the same result.

       

      Print the lines up to and including the line with ‘j’ as second letter

       

      awk -F, '$2=="j" {print; exit} 1' demo
      a,b,c
      b,d,b
      c,j,k

       

      When the pattern $2=="j" is matched the line is printed, then the program exits.

       

      Print the lines starting with the line with ‘j’ as second letter

       

      awk -F, '$2=="j" {f=1} f' demo
      c,j,k
      x,e,d
      s,r,x
      m,n,o

       

      When the pattern $2=="j" is matched, the flag ‘f’ is ‘turned on: the variable ‘f’ is set equal to 1, meaning ‘f’ is true. The flag doesn’t have to be called ‘f’. It can be called ‘chrysanthemum’ or ‘holysmoke’ or ‘qqqqq’ or ‘x’ or any other simple string.

      The ‘f’ at the end is AWK shorthand again, like the ’1′ used above. It means if ‘f’ is true, print the line. Since the flag was turned on earlier — when the pattern $2=="j" was matched in the line c,j,k — that line is printed.

       

      Print the lines starting just after the line with ‘j’ as second letter

       

      awk -F, '$2=="j" {f=1; next} f' demo
      x,e,d
      s,r,x
      m,n,o
      
      awk -F, 'f; $2=="j" {f=1}' demo
      x,e,d
      s,r,x
      m,n,o

       

      In the first command, the flag is turned on when the line c,j,k is read, but then the ‘next’ command tells AWK to drop whatever it’s doing and move to the next line, so the ‘f’ at the end of the command isn’t acted upon and c,j,k doesn’t get printed.

      An alternative is the second command. Here the first instruction tells AWK to print the line if the flag ‘f’ is on. When the c,j,k line is reached, the flag isn’t yet on and the line isn’t printed. The flag is only turned on after the pattern $2=="j" is matched. The order of instructions in an AWK command is important!

       

      Print the lines from the first line with ‘c’ as third letter to the first line with ‘s’ as first letter, inclusive

       

      awk -F, '$3=="c" {f=1} $1=="s" {print; f=0} f' demo
      a,b,c
      b,d,b
      c,j,k
      x,e,d
      s,r,x

       

      The flag is turned off when the s,r,x line is read, so the last line of demo (m,n,o) isn’t printed.

       

      Print the lines from the first line with ‘c’ as third letter up to, but not including, the first line with ‘s’ as first letter

       

      awk -F, '$3=="c" {f=1} $1=="s" {f=0} f' demo
      a,b,c
      b,d,b
      c,j,k
      x,e,d

       

      The line with s,r,x isn’t printed because the flag is turned off before AWK is told to print the line if the flag is true.

       

      Print the lines between the first line with ‘c’ as third letter and the first line with ‘s’ as first letter

       

      awk -F, '$3=="c" {f=1; next} $1=="s" {f=0} f' demo
      b,d,b
      c,j,k
      x,e,d

       

      awk -F, '$1=="s" {f=0}; f; $3=="c" {f=1}' demo
      b,d,b
      c,j,k
      x,e,d

       

      The first command follows the rules demonstrated above. The second command looks a little strange at first but is very logical. The $3=="c" line doesn’t get printed because when AWK processes it, the instruction to print a line when the flag is on (f) appears before the flag has been turned on ({f=1}). The next 3 lines get printed because the flag is on. The $1=="s" line doesn’t get printed because the flag is turned off ({f=0}) before AWK sees the instruction f.

       

      Flags can be turned on and off repeatedly as AWK processes a file. As an example, here’s a list of fruit names in a file called fruit:

       

      pear
      apple
      cherry
      orange
      lemon
      raspberry
      apple
      loquat
      feijoa
      orange
      loquat

       

      Print the lines from ‘apple’ to ‘orange’, inclusive

       

      awk '/apple/ {f=1} /orange/ {print; f=0} f' fruit
      apple
      cherry
      orange
      lemon
      raspberry
      apple
      loquat
      feijoa
      orange

       

      Print the lines from ‘apple’ to ‘orange’, but not including ‘apple’ and ‘orange’

       

      awk '/orange/ {f=0}; f; /apple/ {f=1} f' fruit
      cherry
      loquat
      feijoa

       

      Print the lines between the first ‘apple’ and ‘orange’, but not the second, and vice-versa

      These commands are based on a suggestion from developer ‘waldner’:

       

      awk '/orange/ {f=0} ; f; && c==1; /apple/ {f=1; c++}' fruit
      cherry

       

      awk '/orange/ {f=0} ; f; && c==2; /apple/ {f=1; c++}' fruit
      loquat
      feijoa

       

      To understand how that first command works, it helps to follow AWK as it reads fruit one line at a time.

      The first line (‘pear’) doesn’t match ‘apple’ or ‘orange’ and the flag isn’t on, so AWK does nothing.

      The second line (‘apple’) doesn’t match ‘orange’ and the flag isn’t on, so AWK ignores the first and second instructions in the command. The line matches ‘apple’, so AWK turns on the flag and sets a counter variable ‘c’ and starts incrementing it from 1 (the default starting number for a counter in AWK). No printing yet.

      The third line is ‘cherry’. The flag is on and the counter reads ’1′ (for 1 ‘apple’ found so far), so the line gets printed, following the instruction f && c==1.

      The fourth line is ‘orange’. The flag is turned off, and nothing gets printed by the second instruction in the command.

      Nothing for AWK to match or do with the next 2 lines, ‘lemon’ and ‘raspberry’, since the flag is off.

      Now another ‘apple’ line and the flag is turned on again and the counter gets incremented to ’2′. Although the flag is on, none of the following lines get printed because the counter is at 2, and printing only happens when the counter is at 1.

      The second command has a similar logic, except that printing only happens when the counter is at 2.

       

      The flag commands shown above are OK for finding lines between a first starting pattern and a first ending pattern. If the situation is more complicated, as in this list of fruit names (a file named tricky), things get tricky:

       

      pear
      apple
      apple
      cherry
      orange
      orange
      lemon
      raspberry
      apple
      strawberry
      apple
      loquat
      feijoa
      orange
      loquat

       

      Here the commands won’t work for finding just the names between ‘apple’ and ‘orange’. For example:

       

      awk '/orange/ {f=0} ; f; /apple/ {f=1}' tricky
      apple
      cherry
      strawberry
      apple
      loquat
      feijoa

       

      AWK has followed its instructions, and returned both the second ‘apple’ in line 3 and the ‘strawberry’ and ‘apple’ in lines 9 and 10.

      To get just the names between the closest-occurring ‘apple’ and ‘orange’, two flags can be used:

       

      awk '/orange/ {f=g=0} ; f && g; /apple/ && !f {f=1;next}; /apple/ && f {g=1}' tricky
      cherry
      loquat
      feijoa

       

      Here a line is printed only if both flags, ‘f’ and ‘g’, are on. Note that this particular trick will suit this particular file, but it isn’t a general solution! Two general solutions were offered by contributors Ed Morton and ‘pk’ when I posted the problem on the comp.lang.awk forum. As applied to tricky, both solutions accumulate lines between ‘apple’ and ‘orange’ in a variable. Morton’s solution (split over two lines for clarity):

       

      awk '/orange/ { if (f) printf "%s", buf; f=0 }; > f { buf = buf $0 ORS }; /apple/ { buf=""; f=1 }' tricky
      cherry
      loquat
      feijoa

       

      If ‘apple’ is matched, a flag is turned on and the ‘buf’ variable is emptied. After ‘apple’ has been matched, the next lines (not matching ‘orange’ or ‘apple’) are added to the ‘buf’ variable because ‘f’ is true, and separated with the output record separator (ORS, here a newline). If ‘orange’ is matched and ‘f’ is true (because it has been preceded by ‘apple’), the contents of the ‘buf’ variable are printed and the flag is turned off.

      The general solution from ‘pk’ looks like this as applied to tricky (again split over two lines for clarity):

       

      awk '/apple/{ f=1; b=s=""; next }; /orange/ && f {f=0; print b; b=s=""; next}; > f { b=b s $0; s=RS }' tricky
      cherry
      loquat
      feijoa

       

      This works like Morton’s solution, but uses a different order of instructions and sets the record separator as a variable.

      ———

      Trouver les parenthèses manquantes

      Recently I was checking for unmatched braces in a big text file with nearly half a million lines (300+ MB). Was there a closing brace for every opening brace?

      The text file was called ‘beetle’ and was actually a tab-separated table with each line divided into 77 fields. What I wanted to do was find any lines in which unmatched braces appeared within fields. Here’s the command I used:

       

      awk -F"\t" '{for (i=1;i<=NF;i++) if (split($i,a,"(") != split($i,b,")")) {print NR": "$0; next}}' beetle > unmatched

       

      The command took 1 minute 13 seconds to execute, which isn’t bad for an operation that checked 36,036,077 data fields (with an Intel i3 dual core processor and 4 GB of RAM).

       

      time awk -F"\t" '{for (i=1;i<=NF;i++) if (split($i,a,"(") != split($i,b,")")) {print NR" : "$0; next}}' beetle > unmatched
      real  1m13.380s
      user  1m13.364s
      sys   0m0.064

       

      EXPLICATIONS

       

      cat demo
      a(aaa)     bbbb      (cccc(
      dddd       e(e(ee)   fff)f
      gg(g)      hhh(h     ii(i)i

       

      AWK has a ‘split’ function which takes 3 or 4 arguments. The first argument is the string to be split and the third is the character or characters on which to do the splitting. The second argument is the name of an array into which the split-out bits will be stored, and the fourth (optional) argument is an array containing the separators. What ‘split’ returns is the number of split-out items in the array.

      In the command below, each line in ‘demo’ is split using ‘(‘ as a separator and the number of split-out items is printed for each line:

       

      awk '{print split($0,a,"(")}' demo
      4
      3
      4

       

      Note that AWK found 4 split-out items in the first line, namely a, aaa)[tab]bbbb[tab], cccc plus an empty item separated from the rest by ‘(‘. In other words, the number of items put into an array by ‘split’ will always be just 1 more than the number of separators. Note also that AWK emptied the array ‘a’ before splitting the next line.

      Repeating the command with ‘)’ as separator and loading an array ‘b’, we get:

       

      awk '{print split($0,b,")")}' demo
      2
      3
      3

       

      Now to see whether the number of opening and closing braces is the same in each line. In the following command, AWK is asked to check whether the same number of split-out items is found for each brace type, and if not, then the line number is printed followed by the whole line:

       

      awk '{if (split($0,a,"(") != split($0,b,")")) print NR" : "$0}' demo
      1: a(aaa)    bbbb    (cccc(
      3: gg(g)g    hhh(h   ii(i)i

       

      That worked well, but note that line 2 only has matching braces as a whole line. Fields 2 and 3 in line 2 both have unmatched braces. To look within fields, the full command above uses a for loop to do the checking on each field in turn. If unmatched braces are found in any field, AWK prints out the line number and the whole line, then jumps to the next line following the ‘next’ instruction.

      The full command isn’t perfect because it won’t find a line in which a field has braces matched ‘backwards’, like this: aa)aaa(a. I checked that possibility with another AWK command using a rather complicated regex. Here the command is looking at ‘demo_new’ with an added line including ‘backwards’ braces:

       

      cat demo_new
      a(aaa)   bbbb     (cccc(
      dddd     e(e(ee)  fff)f
      gg(g)g   hhh(h    ii(i)i
      jjjj     )kkk(k   llll

       

      awk -F"\t" '{for (i=1;i<=NF;i++) if ($i ~ /^[^()]*\)[^()]*\(/) print NR": "$0}' demo_new
      4: jjjj  )kkk(k  llll

       

      There were no such lines in ‘beetle’, but the command at the beginning of this article did find 35 lines in ‘beetle’ containing fields with unmatched braces. I checked the 35 lines individually to see what the problem was (typo? truncated string?), then fixed each one with sed. For example I repeated this process for unmatched square brackets ([]), curly brackets ({}) and greater-than/less-than arrows (<>).

      Scripting an arithmeticker

      Voici une calculatrice :

       

       

      En pressant ENTREE, la fenêtre est remplacée par une autre qui affiche le résultat :

       

       

      En pressant ENTREE, cette dernière est remplacée par la première. Si on presse ESC, la fenêtre se ferme.

       

      --selectable-labels permet de sélectionner le résultat et pouvoir le copier ailleurs avec le clic-milieu :

       

      #!/bin/bash
      
      while true ; do
      
         var1=$(yad --entry --geometry=+1600+300 --no-buttons --text="Entrez votre calcul: ")
      
         if [ ! -z "$var1" ] ; then
            var2=$(echo "scale=5; $var1" | bc)
            yad --geometry=+1600+500 --selectable-labels --title="Resultat" --text="<b>$var2</b>" --text-align=center
         else
            exit
         fi
      
         if [ $? == 0 ]; then
            continue
         else
            break
         fi
      
      done
      
      exit

 

Aucun commentaire

 

Laissez un commentaire