156

I have a command, for example: echo "word1 word2". I want to put a pipe (|) and get "word1" from the command.

echo "word1 word2" | ....

What should I put after the pipe?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Neuquino
  • 11,580
  • 20
  • 62
  • 76

13 Answers13

236

AWK is a good option if you have to deal with trailing whitespace because it'll take care of it for you:

echo "   word1  word2 " | awk '{print $1;}' # Prints "word1"

cut won't take care of this though:

echo "  word1  word2 " | cut -f 1 -d " " # Prints nothing/whitespace

'cut' here prints nothing/whitespace, because the first thing before a space was another space.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mattbh
  • 5,230
  • 2
  • 27
  • 27
81

There isn't any need to use external commands. Bash itself can do the job. Assuming "word1 word2" you got from somewhere and stored in a variable, for example,

$ string="word1 word2"
$ set -- $string
$ echo $1
word1
$ echo $2
word2

Now you can assign $1, $2, etc. to another variable if you like.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
  • 13
    +1 for using only shell built-ins and `stdin`. @Matt M. `--` means `stdin`, so `$string` is being passed in as `stdin`. `stdin` is whitespace-separated into arguments `$1`, `$2`, `$3`, etc. - just like when a Bash program evaluates arguments (e.g. check `$1`, `$2`, etc.), this approach takes advantage of the shell's tendency to split the `stdin` into arguments automatically, removing the need for `awk` or `cut`. – Caleb Xu Apr 11 '14 at 01:38
  • 4
    @CalebXu Not stdin, `set` sets the shell arguments. – Guido Nov 14 '14 at 14:54
  • 9
    `word1=$(IFS=" " ; set -- $string ; echo $1)` Set IFS to correctly recognize the space between the words. Wrap in parentheses to avoid clobbering the original content of $1. – Steve Pitchers May 15 '15 at 10:27
  • This is broken as it's subject to pathname expansion. Try it with `string="*"`. Surprise. – gniourf_gniourf Mar 14 '18 at 17:55
  • Good answer, because this is valid not only for Bash, but even for the traditional Bourne shell as well. – cesss Sep 13 '20 at 21:33
  • It can be even simpler: `arr=(word1 word2)` and `echo $arr` (in the `echo` it "defaults" to the first element). Or if the string is already in a variable: `string="word1 word2"`, `arr=($string)`, and `echo $arr` – Peter Mortensen Apr 25 '21 at 19:10
37

I think one efficient way is the use of Bash arrays:

array=( $string ) # Do not use quotes in order to allow word expansion
echo ${array[0]}  # You can retrieve any word. Index runs from 0 to length-1

Also, you can directly read arrays in a pipe-line:

echo "word1 word2" | while read -a array; do echo "${array[0]}" ; done
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Isaías
  • 463
  • 4
  • 7
34
echo "word1 word2 word3" | { read first rest ; echo $first ; }

This has the advantage that is not using external commands and leaves the $1, $2, etc. variables intact.

John Marter
  • 701
  • 7
  • 4
20

Using shell parameter expansion %% *

Here is another solution using shell parameter expansion. It takes care of multiple spaces after the first word. Handling spaces in front of the first word requires one additional expansion.

string='word1    word2'
echo ${string%% *}
word1

string='word1    word2      '
echo ${string%% *}
word1

Explanation

The %% signifies deleting the longest possible match of  * (a space followed by any number of whatever other characters) in the trailing part of string.

Serge Stroobandt
  • 28,495
  • 9
  • 107
  • 102
17

You could try AWK:

echo "word1 word2" | awk '{ print $1 }'

With AWK it is really easy to pick any word you like ($1, $2, etc.).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mfloryan
  • 7,667
  • 4
  • 31
  • 44
15

If you are sure there are no leading spaces, you can use Bash parameter substitution:

$ string="word1  word2"
$ echo ${string/%\ */}
word1

Watch out for escaping the single space. See here for more examples of substitution patterns. If you have Bash > 3.0, you could also use regular expression matching to cope with leading spaces - see here:

$ string="  word1   word2"
$ [[ ${string} =~ \ *([^\ ]*) ]]
$ echo ${BASH_REMATCH[1]}
word1
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dsl101
  • 1,715
  • 16
  • 36
13

I wondered how several of the top answers measured up in terms of speed. I tested the following:

1 @mattbh's

echo "..." | awk '{print $1;}'

2 @ghostdog74's

string="..."; set -- $string; echo $1

3 @boontawee-home's

echo "..." | { read -a array ; echo ${array[0]} ; }

and 4 @boontawee-home's

echo "..." | { read first _ ; echo $first ; }

I measured them with Python's timeit in a Bash script in a zsh terminal on macOS, using a test string with 215 5-letter words. I did each measurement five times (the results were all for 100 loops, best of 3), and averaged the results:

Method       Time
--------------------------------
1. awk       9.2 ms
2. set       11.6 ms (1.26 * "1")
3. read -a   11.7 ms (1.27 * "1")
4. read      13.6 ms (1.48 * "1")
henry
  • 4,244
  • 2
  • 26
  • 37
  • 1
    Weird that you could measure 3 in dash, since dash doesn't support arrays (`read -a` is invalid in dash). – gniourf_gniourf Mar 14 '18 at 17:58
  • Yeah that is weird. I ruled that one out, did the speed tests, then thought "why'd I leave that one out" and added it in. Removing it now, and I may rerun things later to make sure I didn't have some mistake – henry Mar 14 '18 at 19:31
8
echo "word1 word2" | cut -f 1 -d " "

cut cuts the first field (-f 1) from a list of fields delimited by the string " " (-d " ").

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
lajuette
  • 997
  • 1
  • 7
  • 18
6

read is your friend:

  • If string is in a variable:

    string="word1 word2"
    read -r first _ <<< "$string"
    printf '%s\n' "$first"
    
  • If you're working in a pipe: first case: you only want the first word of the first line:

    printf '%s\n' "word1 word2" "line2" | { read -r first _; printf '%s\n' "$first"; }
    

    second case: you want the first word of each line:

    printf '%s\n' "word1 word2" "worda wordb" | while read -r first _; do printf '%s\n' "$first"; done
    

These work if there are leading spaces:

printf '%s\n' "   word1 word2" | { read -r first _; printf '%s\n' "$first"; }
gniourf_gniourf
  • 44,650
  • 9
  • 93
  • 104
1

As Perl incorporates AWK's functionality, this can be solved with Perl too:

echo " word1 word2" | perl -lane 'print $F[0]'
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
tssch
  • 734
  • 8
  • 25
  • That actually works, even with the leading zero, but an explanation would be in order. Please respond by [editing your answer](https://stackoverflow.com/posts/41869233/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Apr 25 '21 at 19:19
1

If you don't mind installing a new command, I would recommend choose

It has the simplest and most intuitive interface of all alternatives:

echo "word1 word2" | choose 0
Klas Mellbourn
  • 42,571
  • 24
  • 140
  • 158
0

I was working with an embedded device which had neither Perl, AWK or Python and did it with sed instead. It supports multiple spaces before the first word (which the cut and bash solutions did not handle).

VARIABLE="  first_word_with_spaces_before_and_after  another_word  "
echo $VARIABLE | sed 's/ *\([^ ]*\).*/\1/'

This was very useful when grepping ps for process IDs since the other solutions here using only Bash was not able to remove the first spaces which ps uses to align.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Johan Bjäreholt
  • 731
  • 1
  • 11
  • 24