0

I have a file with n rows and 4 columns, and I want to read the content of the 2nd and 3rd columns, row by row. I made this

awk 'NR == 2 {print $2" "$3}' coords.txt

which works for the second row, for example. However, I'd like to include that code inside a loop, so I can go row by row of coords.txt, instead of NR == 2 I'd like to use something like NR == i while going over different values of i.

I'll try to be clearer. I don't want to wxtract the 2nd and 3rd columns of coords.txt. I want to use every element idependently. For example, I'd like to be able to implement the following code

for (i=1; i<=20; i+=1)
        awk 'NR == i {print $2" "$3}' coords.txt > auxfile
        func(auxfile)
end

where func represents anything I want to do with the value of the 2nd and 3rd columns of each row.

I'm using SPP, which is a mix between FORTRAN and C.

How could I do this? Thank you

Ed Morton
  • 188,023
  • 17
  • 78
  • 185
Pablo
  • 87
  • 5
  • 1
    `awk 'function func(param) { anything_with_param(); } { func($2 " " $3) }` ? `awk '{for (i=1;i<=NF;++i) { use_each_param_separately($i) }}'`? How is `SPP` related - you seem to be using `awk`. – KamilCuk Mar 02 '21 at 20:32
  • 1
    Are you saying you're calling awk from something called "spp" rather than from Windows or a Unix shell? You should add a "spp" tag if so - how to pass the value of a "spp" variable to an awk script will depend on how you access the value of "spp" variables if that's really what you need to do. – Ed Morton Mar 02 '21 at 20:53
  • @patrick I see you added the tag for SPP meaning "Serial Port Profile" but in your previous question you provided a reference for SPP to a document about "Subset Preprocessor Language" - adding the wrong tag is worse than adding no tag. I don't see any existing tag for this so I created a new tag `spplang` for you and added it to your question. – Ed Morton Mar 03 '21 at 17:52

3 Answers3

1

It is of course inefficient to invoke awk 20 times. You'd want to push the logic into awk so you only need to parse the file once.

However, one method to pass a shell variable to awk is with the -v option:

for ((i=1; i<20; i+=2))  # for example
do
    awk -v line="$i" 'NR == line {print $2, $3}' file
done

Here i is the shell variable, and line is the awk variable.

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • The OP is calling awk from a [SPP program](https://www.mn.uio.no/astro/english/services/it/help/visualization/iraf/SPPManual.pdf) apparently, not from a shell. – Ed Morton Mar 03 '21 at 17:46
0

something like this should work, there is no shell loop needed.

 awk 'BEGIN {f="aux.aux"}
      NR<21 {close(f); print $2,$3 > f; system("./mycmd2 "f)}' file

will call the command with the temp filename for the first 20 lines, the file will be overwritten at each call. Of course, if your function takes arguments or input from stdin instead of file name there are easier solution.

Here ./mycmd2 is an executable which takes a filename as an argument. Not sure how you call your function but this is generic enough...

Note also that there is no error handling for the external calls.

karakfa
  • 66,216
  • 7
  • 41
  • 56
  • hmmm..... wouldn't this close "f" upon NR == 1 ? not sure how it'll execute since you closed the aux file before the first print ? am i missing something ? – RARE Kpop Manifesto Mar 08 '21 at 20:57
  • @RAREKpopManifesto skepticism is a useful attribute, but this is so easy to test and verify. The file will be recreated for each record. If you don't close each time it will append to it. – karakfa Mar 08 '21 at 21:00
  • then why need the aux file at all ? just system("./mycmd2 \047" $2 "\047 \047" $3 "\047"); will do. ( ps octal \047 means single-quote, in case the parameters being passed in aren't a contiguous block. escape single quotes inside $2 or $3 if need be) – RARE Kpop Manifesto Mar 08 '21 at 21:11
  • OP's script seems to take a filename instead of the arguments or stdin. Not efficient but that's the requirement. – karakfa Mar 08 '21 at 22:21
  • then system("printf \047%s\\n\047 \047" $2 "\047 \047" $3 "\047 | ./mycmd2 \047/dev/stdin\047; "); – RARE Kpop Manifesto Mar 09 '21 at 00:27
0

the hideous system( ) only way in awk would be like

system("printf \047%s\\n\047 \047" $2 "\047 \047" $3 "\047 | func \047/dev/stdin\047; "); 

if the func( ) OP mentioned can be directly called by GNU parallel, or xargs, and can take in values of $2 + $3 as its $1 $2, then OP can even make it all multi-threaded like

{mawk/mawk2/gawk} 'BEGIN { OFS=ORS="\0"; } { print $2, $3; } (NR==20) { exit }' file \
    \
    | { parallel -0 -N 2 -j 3 func | or | xargs -0 -n 2 -P 3 func }
RARE Kpop Manifesto
  • 2,453
  • 3
  • 11