Say I run the command SayStuff

$ SayStuff

and the output is

Watermelons and cucumbers

Now. Say I want to extract the substring cucumbers from the output and pipe it into something.
The way I would go about this programmatically would be to split the output into an array by the delimiter Space and reference it by ArrayName[2]. I am fairly new to shell scripts and have only succeeded in digging up semi-cryptic cut examples, none of which made sense.

Any ideas?

3 Answers 3

$ echo "Watermelons and cucumbers" | cut -d ' ' -f 3

The -d ' ' tells cut to split on spaces. -f 3 selects the third column.

You can also use awk, which does the splitting based on space already and makes the columns available as $1, $2, …

$ echo "Watermelons and cucumbers" | awk '{ print $3 }'
  • Note that cut will not handle a variable number of spaces, while awk do.
    – Zitrax
    Feb 10, 2016 at 12:13

I would probably use one of the options already given by @slhck but here are a few more ways of doing this:

  1. Using arrays, as you would in any other language:

     $ foo=( $(SayStuff) ) 
     $ echo ${foo[2]}

    The var=() declares an array, $(command) saves the output of the command. So, foo=( $(SayStuff) ) stores the output of SayStuff into the array foo and yuou then echo its third element with ${foo[2]}.

  2. sed

     $ SayStuff | sed 's/.* \(.*\)/\1/'

    The sed command will substitute (s///) everything with the last word. The regex matches anything up to a space (.* ) which will match everything up to the last space and then captures the last word (\(.*\). Since the word has been captures, we can refer to it as \1.

    A simpler version:

     $ SayStuff | sed 's/.* //'
  3. bash

     $ foo=$(SayStuff); echo ${foo##* } 

    This uses bash's string manipulation abilities, see here for more details.

  4. More bash

     $ SayStuff | while read a b c; do echo $c; done
  5. Perl, where of course, there are many ways to do this:

     $ SayStuff | perl -lane 'print $F[$#F]'

    The -a makes perl behave like awk, splitting lines at whitespace and saving into the array @F. We then print the last element of @F ($#F is the number of elements in @F). The -l tells perl to add a newline to each print statement, the -n that it should process STDIN line by line and -e that it should run the script given at the command line.

     $ SayStuff | perl -pe 's/.* //'

    The options were explained above, we are just deleting everything till the last space and printing (-p).

     $ perl -le 'print $ARGV[$#ARGV]' $(SayStuff)

    Here we are passing Watermelons and cucumbers as arguments, which perl will save in the @ARG array and so, we print the last element of @ARG.

  6. trickery. This one uses sed to convert spaces to newlines and then tail to print only the last line.

     $ SayStuff | sed 's/ /\n/g' | tail -n 1
  7. grep and regular expressions, using -o which prints only the matched string.

     $ SayStuff | grep -Po '\w+$' 
  8. cheating

     $ SayStuff | grep -o cucumbers

Here is some more explanation:

Usage: cut OPTION... [FILE]...

Print selected parts of lines from each FILE to standard output.

   -d, --delimiter=DELIM
          use DELIM instead of TAB for field delimiter

   -f, --fields=LIST
          select only these fields;  also print any line that contains  no
          delimiter character, unless the -s option is specified

So if you need the 3rd field and it is delimited by spaces ' ' then it is

$ echo "Watermelons and cucumbers" | cut -d ' ' -f 3  

If you want the LAST field you probably should use awk.
In this case it becomes:

$ echo "Watermelons and cucumbers" | awk '{ print $NF }'

In awk NF is the number of fields in the line so $NF means the last field in the line.


You must log in to answer this question.

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