4

I have this file on Linux:

 14:00:01.071 5255  604177
4 14:00:01.074 4608  1415742
 14:00:01.074 18398  1122001
2 14:00:01.074 11723  155575
5 14:00:01.075 4695  885808

Desired Output:

 14:00:01.071 5255  604177
 14:00:01.074 4608  1415742
 14:00:01.074 18398 1122001
 14:00:01.074 11723 155575
 14:00:01.075 4695  885808

Command Used:

gawk '{ print $NF-1, $NF}' filename

But it prints only the last two columns.

2
  • 9
    Oh, come on. 1) that script does not print the last 2 columns (you're missing parens around NF-1) and 2) assuming you do have a script to print the last column with NF and the 2nd-last column with NF-1, I struggle to believe you couldn't figure out how to build on that pattern to also print the 3rd-last column.
    – Ed Morton
    Commented Aug 7, 2019 at 15:28
  • Does this answer your question? Print range of columns comma-separated, and the rest without comma-separation Commented Jan 13, 2021 at 15:18

7 Answers 7

7

It is quite incorrect, $NF-1 would print the value of the last column subtracted by one. You need to group the command within (..), since NF is a variable

gawk 'NF>=3{ print $(NF-2), $(NF-1), $NF}' file

The part NF>=3 is to safely validate you are printing the last 3 fields on lines that is guaranteed to have at least 3 fields.

7

Assuming

  1. The delimiter is a space
  2. You want all but the first column, which may be blank, but will have a delimiter
  3. There's only one delimiter between columns

then you can use cut -d' ' -f2- to print, from a space-separated values file, the contents from the second column to the last one.

1
  • I'd suggest adding ...| column -t to have the output properly aligned.
    – markgraf
    Commented Aug 9, 2019 at 6:43
4
$ awk '{ print $(NF-2), $(NF-1), $NF}' file1
14:00:01.071 5255 604177
14:00:01.074 4608 1415742
14:00:01.074 18398 1122001
14:00:01.074 11723 155575
14:00:01.075 4695 885808
0
3

With GNU grep, you can do:

grep -Eo '\S+\s+\S+\s+\S+\s*$'

Which would preserve the spacing in the input. Note that lines that contain fewer than 3 fields are skipped.

POSIXly, the equivalent would be:

S='[^[:space:]]\{1,\}' s='[[:space:]]\{1,\}'
sed -n "s/$S$s$S$s${S}[[:space:]]*$/\\
&/;s/.*\n//p"
2

I tested with below command and it worked fine

 sed "s/^[0-9]\{1,\}//g" filename| sed -r "s/^\s+//g"

output

14:00:01.071 5255  604177
14:00:01.074 4608  1415742
14:00:01.074 18398  1122001
14:00:01.074 11723  155575
14:00:01.075 4695  885808
2
  • 2
    It should be noted that this command removes digits in the first column as opposed to printing only the last 3 columns. It's thus hard-coded to expect a certain number of columns as input.
    – Jeff Schaller
    Commented Aug 7, 2019 at 15:26
  • 2
    It's also unnecessarily GNU-specific for -r and \s, using 2 seds and a pipe when 1 could do the same thing, and using double quotes instead of single unnecessarily.
    – Ed Morton
    Commented Aug 7, 2019 at 21:41
0

awk '{print $(NF-2),$(NF-1),$(NF)}' file.txt

Where NF is the number of fields in your file.

0

Since the question is tagged perl

$ perl -lane 'print "@F[-3..-1]"' ip.txt
14:00:01.071 5255 604177
14:00:01.074 4608 1415742
14:00:01.074 18398 1122001
14:00:01.074 11723 155575
14:00:01.075 4695 885808
  • -l strip newlines from input lines, and add it to end of string when print is used
  • -a autosplit input based on whitespaces, accessible via @F array
  • print "@F[-3..-1]" print the desired fields, the default delimiter when array is specified within double quotes is single space
    • -1 refers to last field, -2 refers to second last field, etc
    • .. is range operator

Use perl -lane 'print "@F[-3..-1]" if $#F > 2' if you do not want lines with less than 3 fields to be displayed. $#F gives the last index of array, i.e. size of array minus 1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .