59

I have this input, which is displayed in columns. I would like to get the last column of this sample:

[  3]  1.0- 2.0 sec  1.00 MBytes  8.39 Mbits/sec
[  3]  2.0- 3.0 sec   768 KBytes  6.29 Mbits/sec
[  3]  3.0- 4.0 sec   512 KBytes  4.19 Mbits/sec
[  3]  4.0- 5.0 sec   256 KBytes  2.10 Mbits/sec
...

If I use

cut -d\  -f 13

I get

Mbits/sec
6.29
4.19
2.10

because sometimes there are additional spaces in between.

  • The last column is Mbits/sec, is that what you want or the 2 last columns? – terdon Jan 18 '14 at 14:43
  • 1
    I only want to get the 2nd last column, only the numbers – rubo77 Aug 11 '15 at 0:37
79

If we use tr command along with squeeze option (-s flag ) to convert all multiple consecutive spaces to a single space and then perform cut operation with space as delimiter – we can access the required column carrying the numbers.

Refer to the code snipped bellow:

cat file | tr -s ' ' | cut -d ' ' -f 8

| improve this answer | |
  • 4
    BSD cut offers -w for such cases! – Michael-O Mar 24 at 10:05
  • @Michael-O Nice! I'm using cut from GNU coreutils on Arch Linux and it lacks such an option. – Mehdi Sadeghi May 26 at 12:40
  • 2
    this can be done without cat: tr -s ' ' file | cut -d ' ' -f 8 – Josh Aug 26 at 14:16
24

To answer your question literally:

sed 's/   */:/g' | cut -d : -f 5

or

awk -F '  +' '{print $5}'

But that won't do if the number in brackets reaches 10, etc. If you're only interested in the numbers, you could remove everything else.

sed 's/[^.0-9][^.0-9]*/:/g' | cut -d : -f 6
| improve this answer | |
  • yes, sure only the numbers, but only your 3rd example works correctly – rubo77 Jan 18 '14 at 0:08
  • @rubo77 Works for me. The first two examples do exactly what you ask in your title. Or did you want to strip off the unit as well? In that case, add | sed 's/ .*//' at the end of the first two examples. Of course there are many other ways to do it. – Gilles 'SO- stop being evil' Jan 18 '14 at 0:13
  • a bit shorter with + instead of *: cat test | sed 's/[^.0-9]\+/:/g' | cut -d : -f 6 – rubo77 Sep 1 '16 at 8:29
  • @rubo77 If your sed supports it, that is. It's supported by GNU and BusyBox but not by e.g. BSD or Solaris. POSIX specifies + and ? in ERE but leaves \+ and \? in BRE undefined. – Gilles 'SO- stop being evil' Sep 1 '16 at 8:57
  • So the right option for columned input into cut would be -c35-38 – rubo77 Jun 20 at 2:33
7

These commands will all print the last column of a space separated file:

  • awk '{print $NF}' file

    in awk, NF is the number of fields and $NF is the last field.

  • perl -lane 'print $F[$#F]' file

    -a splits the file on whitespace into the array @F, $#F is the number of elements in the array so $F[$#F] is the last element. The -n means read the file given on the command line and apply the script passed with -e to each line. -l just adds a newline character (\n) to each print statement.

  • sed 's/.* //g'

    a simple regular expression that matches everything to the last space and deletes it, leaving only the last column.

  • rev file | cut -d' ' -f 1 | rev

    rev reverses its output so the last field is the first, cut with delimiter space to print it and rev to reverse the text back to normal. This won' t work if you have consecutive whitespace.

Based on your input, I am guessing you don't actually want the last column but the penultimate one or the two last ones. In that case use these to print the last 2 (8.39 Mbits/sec):

awk '{print $(NF-1),$NF}' file 
perl -lane 'print "$F[$#F-1] $F[$#F]"' file 
sed 's/.* \(.* .*\)/\1/' file 
rev file | cut -d' ' -f 1,2 | rev

and these to print the penultimate (8.39):

awk '{print $(NF-1)}' file 
perl -lane 'print $F[$#F-1]' file 
sed 's/.* \(.*\) .*/\1/' file 
rev file | cut -d' ' -f 2 | rev
| improve this answer | |
5

You can't separate multiple occurrence of whitespaces using cut as per manual:

Output fields are separated by a single occurrence of the field delimiter character.

unless the text is separated by the same amount or you use tr to remove excess of them.

Otherwise use alternative tools such as awk, sed or ex.

For example:

ex -s +'%norm $2Bd0' +%p +q! foo.txt

Replace +q! with -cwq to save the changes in-place.

| improve this answer | |
1

Use a perl one-liner like so:

perl -lane 'print $F[-2]' input_file

Explanation:

Option -e causes the perl interpreter to look for the script inline, rather than in a file.

Option -n causes the input (file or STDIN from a pipe) to be read line by line.

Option -l strips the input record separator (OS-dependent, newline on UNIX by default) after reading the line, and adds it at the end to every print

Option -a causes each input line to be split on whitespace into array @F, and $F[-2] is the second element counting from the end, which is the field you want. You can also use $F[$#F-1], where $#F is the last index of the array @F, which is slightly less readable.

| improve this answer | |
0

the right option for columned input into cut would be

cut -c35-38
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.