How to print all the columns after a particular number using awk?

ShellAwk

Shell Problem Overview


On shell, I pipe to awk when I need a particular column.

This prints column 9, for example:

... | awk '{print $9}'

How can I tell awk to print all the columns including and after column 9, not just column 9?

Shell Solutions


Solution 1 - Shell

awk '{ s = ""; for (i = 9; i <= NF; i++) s = s $i " "; print s }'

Solution 2 - Shell

When you want to do a range of fields, awk doesn't really have a straight forward way to do this. I would recommend cut instead:

cut -d' ' -f 9- ./infile

###Edit### Added space field delimiter due to default being a tab. Thanks to Glenn for pointing this out

Solution 3 - Shell

awk '{print substr($0, index($0,$9))}'

Edit: Note, this doesn't work if any field before the ninth contains the same value as the ninth.

Solution 4 - Shell

sed -re 's,\s+, ,g' | cut -d ' ' -f 9-

Instead of dealing with variable width whitespace, replace all whitespace as single space. Then use simple cut with the fields of interest.

It doesn't use awk so isn't germane but seemed appropriate given the other answers/comments.

Solution 5 - Shell

Generally perl replaces awk/sed/grep et. al., and is much more portable (as well as just being a better penknife).

perl -lane 'print "@F[8..$#F]"'

Timtowtdi applies of course.

Solution 6 - Shell

awk -v m="\x01" -v N="3" '{$N=m$N ;print substr($0, index($0,m)+1)}'

This chops what is before the given field nr., N, and prints all the rest of the line, including field nr.N and maintaining the original spacing (it does not reformat). It doesn't mater if the string of the field appears also somewhere else in the line, which is the problem with Ascherer's answer.

Define a function:

fromField () { 
awk -v m="\x01" -v N="$1" '{$N=m$N; print substr($0,index($0,m)+1)}'
}

And use it like this:

$ echo "  bat   bi       iru   lau bost   " | fromField 3
iru   lau bost   
$ echo "  bat   bi       iru   lau bost   " | fromField 2
bi       iru   lau bost   

Output maintains everything, including trailing spaces For N=0 it returns the whole line, as is, and for n>NF the empty string

Solution 7 - Shell

Here is an example of ls -l output:

-rwxr-----@ 1 ricky.john  1493847943   5610048 Apr 16 14:09 00-Welcome.mp4
-rwxr-----@ 1 ricky.john  1493847943  27862521 Apr 16 14:09 01-Hello World.mp4
-rwxr-----@ 1 ricky.john  1493847943  21262056 Apr 16 14:09 02-Typical Go Directory Structure.mp4
-rwxr-----@ 1 ricky.john  1493847943  10627144 Apr 16 14:09 03-Where to Get Help.mp4

My solution to print anything post $9 is awk '{print substr($0, 61, 50)}'

Solution 8 - Shell

Using cut instead of awk and overcoming issues with figuring out which column to start at by using the -c character cut command.

Here I am saying, give me all but the first 49 characters of the output.

 ls -l /some/path/*/* | cut -c 50-

The /*/*/ at the end of the ls command is saying show me what is in subdirectories too.

You can also pull out certain ranges of characters ala (from the cut man page). E.g., show the names and login times of the currently logged in users:

       who | cut -c 1-16,26-38

Solution 9 - Shell

To display the first 3 fields and print the remaining fields you can use:

awk '{s = ""; for (i=4; i<= NF; i++) s= s $i : "; print $1 $2 $3 s}' filename

where $1 $2 $3 are the first 3 fields.

Solution 10 - Shell

function print_fields(field_num1, field_num2){
    input_line = $0

    j = 1;
    for (i=field_num1; i <= field_num2; i++){
    	$(j++) = $(i);
	
    }
    NF = field_num2 - field_num1 + 1;
    print $0

    $0 = input_line
}

Solution 11 - Shell

Usually it is desired to pass the remaining columns unmodified. That is, without collapsing contiguous white space.

Imagine the case of processing the output of ls -l or ps faux (not recommended, just giving examples where the last column may contain sequences of whitespace)). We'd want any contiguous white space in the remaning columns preserved so that a file named my file.txt doesn't become my file.txt.

Preserving white space for the remainder of the line is surprisingly difficult using awk. The accepted awk-based answer does not, even with the suggested refinements.

sed or perl are better suited to this task.

sed

echo '1 2 3 4 5 6 7 8 9   10' | sed -E 's/^([^ \t]*[ \t]*){8}//'

Result:

9   10

The -E option enables modern ERE regex syntax. This saves me the trouble of backslash escaping the parentheses and braces.

The {8} is a quantifier indicating to match the previous item exactly 8 times.

The sed s command replaces 8 occurrences of white space delimited words by an empty string. The remainder of the line is left intact.

perl

Perl regex supports the \h escape for horizontal whitespace.

echo '1 2 3 4 5 6 7 8 9   10' | perl -pe 's/^(\H*\h*){8}//'

Result:

9   10

Solution 12 - Shell

ruby -lane 'print $F[3..-1].join(" ")' file

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLazerView Question on Stackoverflow
Solution 1 - ShellAmadanView Answer on Stackoverflow
Solution 2 - ShellSiegeXView Answer on Stackoverflow
Solution 3 - ShellAschererView Answer on Stackoverflow
Solution 4 - ShellSome FoolView Answer on Stackoverflow
Solution 5 - ShellbobbogoView Answer on Stackoverflow
Solution 6 - ShellRobert VilaView Answer on Stackoverflow
Solution 7 - ShellrickydjView Answer on Stackoverflow
Solution 8 - ShellJoeView Answer on Stackoverflow
Solution 9 - ShellRaymond C Borges HinkView Answer on Stackoverflow
Solution 10 - Shellmsol01View Answer on Stackoverflow
Solution 11 - ShellRobin A. MeadeView Answer on Stackoverflow
Solution 12 - ShellkurumiView Answer on Stackoverflow