how to awk from n to n elelment

1

grep -i 'search' var/log/sample.log | less -S | awk '{print $1,$2,$3,$31,$32,$33,$34,$35,$36,$37}'

I want to print from 31 to the end or from 31 to the 34 element only, and I don't want to list them one by one.

Could you reccomend me a for loop I could integrate?

Bonus points if you can suggest solution only with awk.

Please dont suggest cut, as this is not the point.

Thank you.

Cueisa

Posted 2019-12-20T18:16:14.270

Reputation: 11

Answers

0

You can try something like:

awk '{for (i = 31; i <= NF; i++)  printf "%s ",$i;printf "\n"}'

This will print all the field from 31 to the end If you want to have specific limit use code like (to 34 for example):

awk '{for (i = 31; i <= 34; i++)  printf "%s ",$i;printf "\n"}'

Romeo Ninov

Posted 2019-12-20T18:16:14.270

Reputation: 2 062

0

This prints fields 1-3 and 31-last in one line:

awk '
{
    for (i=1; i<=3; i++)
        printf "%s%s", $i, OFS
    for (i=31; i<=NF; i++)
        printf "%s%s", $i, OFS
    printf "%s", ORS
}'

Notes:

  • I don't separate fields with explicit space, I use OFS. The default value of OFS is a space.
  • I don't separate records with explicit newline, I use ORS. The default value of ORS is a newline.

It's good practice to use such standard awk variables. If you ever need non-default values, you won't need to change the code (e.g. awk -v OFS=- …).

The above code is quite simple but you may or may not like its "policy" regarding OFSs: the first for loop will always generate exactly 3 OFSs, even if the input line is empty; and there will always be at least one trailing OFS.


The following variant avoids extra OFSs:

awk '
{
    for (i=1; i<=3 && i<=NF; i++)
        printf "%s%s", (i==1)? "" : OFS, $i
    for (i=31; i<=NF; i++)
        printf "%s%s", OFS, $i
    printf "%s", ORS
}'

Tricks in use:

  • The additional condition i<=NF in the first for loop makes it not print OFSs for fields that don't exist in the input.
  • Instead of printing OFS after a field and trying to suppress the last (trailing) one, we print OFS before a field and suppress it for the first field that gets printed. The point is it's easy to tell which field will be printed as the first in the output (even if NF may vary); it's not so easy to tell which field will be printed as the last (if NF may vary).

On the other hand your example code ({print $1,$2,$3,$31,$32,$33,$34,$35,$36,$37}) prints 10 fields and exactly 9 OFSs between them, even if the input line is empty. I don't know if this is what you need. There is no trailing OFS after the last field printed. To achieve something similar, try this:

awk '
{
    for (i=1; i<=3; i++)
        printf "%s%s", (i==1)? "" : OFS, $i
    for (i=31; i<=NF || i<=37; i++)
        printf "%s%s", OFS, $i
    printf "%s", ORS
}'

If there are 37 or less fields in the input then there will be exactly 9 OFSs; this will behave like your code. Additional fields (38th and further) will generate more OFSs and fields in the output.

Kamil Maciorowski

Posted 2019-12-20T18:16:14.270

Reputation: 38 429

0

The all-awk (except for determining the width of your screen which there's no way to do in awk) equivalent of:

grep -i 'search' var/log/sample.log | less -S | awk '{print $1,$2,$3,$31,$32,$33,$34,$35,$36,$37}'

is with any awk:

awk -v width="$(tput cols)" '
    { $0 = substr($0,1,width) }
    tolower($0) ~ /search/ {
        for (i=1; i<=3; i++) {
            printf "%s%s", $i, OFS
        }
        for (i=31; i<=37; i++) {
            printf "%s%s", $i, (i<37 ? OFS : ORS)
        }
    }
' var/log/sample.log

or with GNU awk for gensub() (untested since you didn't provide any input/output to test against):

awk -v width="$(tput cols)" '
    { $0 = substr($0,1,width) }
    tolower($0) ~ /search/ {
        print gensub(/\s*((\S+\s+){3})(\S+\s+){27}((\S+\s+){6}\S+).*/,"\\1\\4",1)
    }
' var/log/sample.log

Ed Morton

Posted 2019-12-20T18:16:14.270

Reputation: 131