How to print all the columns after a particular number using awk?
ShellAwkShell 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