65

I realize how to do it in python, just with

line = db_file.readline()
ll=string.split(line)

but how can I do the same in bash? is it really possible to do it in a so simple way?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
asdf
  • 2,281
  • 5
  • 28
  • 29

9 Answers9

153
s='foo bar baz'
a=( $s )
echo ${a[0]}
echo ${a[1]}
...
ZoogieZork
  • 11,215
  • 5
  • 45
  • 42
  • 1
    Inline variant: BAR="$(a=($value);echo ${a[1]})" – Austin France Jul 03 '13 at 10:22
  • 1
    This gives a error ./deploy.sh: 7: ./deploy.sh: Syntax error: "(" unexpected Line 7 is where, a=( $s ) is located. – Isuru Pathirana Dec 17 '14 at 16:48
  • 3
    @isuru-buddhika This syntax is specific to Bash; you'll get that syntax error if your script is executed by something other than Bash (e.g. starts with `#!/bin/sh` on a Debian or Ubuntu system). It should work if the script is executed like `bash deploy.sh` or the first line is changed to `#!/usr/bin/env bash`). – ZoogieZork Dec 17 '14 at 18:25
  • 4
    (I cannot add an answer to the question, hence adding as a comment) If you just want to extract the first or last word from (eg) output from a command, you can simply use the shell variable string substitution operators, to remove the first or last section of a string. `desktop:~$ var="first last" desktop:~$ first_word=${var%% *} # space star ! desktop:~$ echo $first_word first desktop:~$ last_word=${var##* } # star space ! desktop:~$ echo $last_word last` – MikeW Nov 12 '15 at 14:20
  • This fails if the input has wildcard characters, e.g. place of `s='foo bar baz'` try `s='* bar baz'` – bitinerant Aug 18 '22 at 09:42
52

If you want a specific word from the line, awk might be useful, e.g.

$ echo $LINE | awk '{print $2}'

Prints the second whitespace separated word in $LINE. You can also split on other characters, e.g.

$ echo "5:6:7" | awk -F: '{print $2}'
6
xioxox
  • 2,526
  • 1
  • 22
  • 22
  • 1
    This is my reason to start using awk just now. Unlike array creation and extra lines. -F: does just explode from : in one just line. Love it, thx. – m3nda Mar 03 '15 at 09:45
  • furthermore: `echo "5::6:7" | awk -F:: '{print $2}'` `6:7` (differently from cut, that takes only one char as delimiter) – ribamar Feb 29 '16 at 11:39
41
echo $line | tr " " "\n"

gives the output similar to those of most of the answers above; without using loops.


In your case, you also mention ll=<...output...>,
so, (given that I don't know much python and assuming you need to assign output to a variable),

ll=`echo $line | tr " " "\n"`

should suffice (remember to echo "$ll" instead of echo $ll)

gawkface
  • 2,104
  • 2
  • 27
  • 29
40

It depends upon what you mean by split. If you want to iterate over words in a line, which is in a variable, you can just iterate. For example, let's say the variable line is this is a line. Then you can do this:

for word in $line; do echo $word; done

This will print:

this
is
a
line

for .. in $var splits $var using the values in $IFS, the default value of which means "split blanks and newlines".

If you want to read lines from user or a file, you can do something like:

cat $filename | while read line
do
    echo "Processing new line" >/dev/tty
    for word in $line
    do
        echo $word
    done
done

For anything else, you need to be more explicit and define your question in more detail.

Note: Edited to remove bashism, but I still kept cat $filename | ... because I like it more than redirection.

Alok Singhal
  • 93,253
  • 21
  • 125
  • 158
  • 6
    Useless use of `cat` - redirect the file like this: `done < "$filename"`. Also, use `for value in "${var[@]}"` in this context instead of an index variable. While in this case the array may be contiguous, Bash supports sparse arrays and `${#var[@]}` may not be the last entry (although `${var[@]: -1}` will be and `indices=(${!a[@]}); count=${#indices[@]}` will give the list of indices and the correct count) – Dennis Williamson Dec 29 '09 at 19:49
  • 1
    @Dennis: All good points. I am used to `cat a | blah` instead of `blah – Alok Singhal Dec 30 '09 at 03:59
  • 2
    This approach will fail if you've good an asterisk (*) in the $line. Bash will substitute if with the file list in the current directory. – crenate May 16 '12 at 09:53
12

do this

while read -r line
do
  set -- $line
  echo "$1 $2"
done <"file"

$1, $2 etc will be your 1st and 2nd splitted "fields". use $@ to get all values..use $# to get length of the "fields".

ghostdog74
  • 327,991
  • 56
  • 259
  • 343
  • 1
    Note that if your `$line` contains e.g. `*`, this will get expanded by bash when doing `set -- $line`, which can have surprising effects. – clacke Jan 13 '14 at 10:53
  • 1
    1) What does the "--" do? 2) What surprising effects can expanding * have? – Xofo Jun 03 '15 at 19:08
11

More simple,

echo $line | sed 's/\s/\n/g'

\s --> whitespace character (space, tab, NL, FF, VT, CR). In many systems also valid [:space:]

\n --> new line

cturiel
  • 119
  • 1
  • 4
10
$ line="these are words"
$ ll=($line)
$ declare -p ll  # dump the array
declare -a ll='([0]="these" [1]="are" [2]="words")'
$ for w in ${ll[@]}; do echo $w; done
these
are
words
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
6

The -a option of read will allow you to split a line read in by the characters contained in $IFS.

Cristian Ciupitu
  • 20,270
  • 7
  • 50
  • 76
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
4

If you already have your line of text in a variable $LINE, then you should be able to say

for L in $LINE; do
   echo $L;
done
Phil Miller
  • 36,389
  • 13
  • 67
  • 90