hhh
hhh

Reputation: 52820

AWK: print every second field with different output inline-separator and different output EOF separator?

This question is related to using awk to print every second field but I am having problems to print it neatly

$ cat printEachSecondColumnValue 
1,11,111,1111,11111
2,22,222,2222,22222
3,33,333,3333,33333
4,44,444,4444,44444
5,55,555,5555,55555
6,66,666,6666,66666
$ gawk -v RS=, -v ORS="\n" '0==NR%2' printEachSecondColumnValue 
11
1111
22
2222
33
3333
44
4444
55
5555
66
6666
$ gawk -v RS=, -v ORS="," '0==NR%2' printEachSecondColumnValue 
11,1111,22,2222,33,3333,44,4444,55,5555,66,6666,

while I want to get

11,1111
22,2222
33,3333
44,4444
55,5555
66,6666

Can you explain the behaviour of the command piece-by-piece and how to define the inline-separator and EOF differently to get the two columns?

Upvotes: 0

Views: 129

Answers (1)

Kaz
Kaz

Reputation: 58510

while I want to get

11,1111
22,2222
33,3333
44,4444
55,5555
66,6666

Pardon this intrusion of the obvious, but that's just

awk 'BEGIN { FS = OFS = ","} { print $2, $4 }'

for the given data.

To print the even fields regardless of how many there are, we can replace the print with a loop:

awk 'BEGIN {
       FS = OFS = ","
     }                                                    
     {                                                                          
       for (i = 2; i <= NF; i += 2) {                                           
         printf "%s", i                                                         
         if (i + 2 <= NF)                                                       
           printf OFS                                                           
       }                                                                        
       printf "\n"                                                              
     }' 

Alternative logic for the commas:

       for (i = 2; i <= NF; i += 2) {
         if (i > 2)
           printf OFS
         printf "%s", i
       }

Now, for something a little different. What if we edit the fields to the set we want? Then we can just print them with print!

awk 'BEGIN { FS = OFS = ","}
     {
       for (i = 2; i <= NF; i += 2) {
         j = i/2
         $j = $i
       }    
       NF = j
       print
     }'

When we assign to NF, it means there are now that many fields. If we change any of the fields, or change NF, then the value of $0 which print prints by default is re-calculated by combining the field values with OFS between them.

Smarter Awk, implemented as a Lisp macro in the TXR Language:

$ txr -e '(awk (:set fs "," ofs fs)
               (t (set f (select f (range 1 : 2)))
                  (prn)))'
1,2,3,4,5,6,7,8,9,10
2,4,6,8,10
1,2,3,4
2,4

Here the (:set ...) clause is for setting up initial variables; fs is the analog of FS and set to the comma; ofs is set to fs.

The t means Boolean true: this clause fires for every record. We then edit the list of fields f by selecting the second, third, fourth, which are indicated by the zero-based list (1 3 5 7 9 ...). We generate an infinite, lazy version of this index list using (range 1 : 2) and feed it to the select function.

Assigning to f causes the record variable rec (analogous to $0) to be re-constituted with ofs. The prn function with no arguments prints rec.

We can get rid of that modification of f and side effect of setting rec by feeding the output of select directly as arguments to prn with apply:

txr -e '(awk (:set fs "," ofs fs)
             (t [apply prn (select f (range 1 : 2))])))'

"Apply prn to the even fields, with ofs being the comma."

Upvotes: 2

Related Questions