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 it's 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.


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.