Bitdiot
Bitdiot

Reputation: 1598

What is the POSIX shell equivalent of bash <<<

I have a variable that looks sort of like this:

msg="newton apple tree"

I want to assign each of these words into separate variables. This is easy to do in bash:

read a b c <<< $msg

Is there a compact, readable way to do this in POSIX shell?

Upvotes: 15

Views: 4722

Answers (3)

chepner
chepner

Reputation: 531808

A here string is just syntactic sugar for a single-line here document:

$ msg="foo * bar"
$ read a b c <<EOF
> $msg
> EOF
$ echo "$a"
foo
$ echo "$b"
*
$ echo "$c"
bar

Upvotes: 34

that other guy
that other guy

Reputation: 123560

To write idiomatic scripts, you can't just look at each individual syntax element and try to find a POSIX equivalent. That's like translating text by replacing each individual word with its entry in the dictionary.

The POSIX way of splitting a string known to have three words into three arguments, similar but not identical to read is:

var="newton apple tree"

set -f
set -- $var
set +f
a=$1 b=$2 c=$3

echo "$a was hit by an $b under a $c"

Upvotes: 11

Charles Duffy
Charles Duffy

Reputation: 295639

It's not pretty, but as a general-purpose solution, you can work around this with a named pipe.

From BashFAQ #24:

mkfifo mypipe
printf '%s\n' "$msg" >mypipe &
read -r a b c <mypipe

printf is more reliable / better-specified than echo; echo behavior varies between implementations if you have a message containing only, say, -E or -n.


That said, for what you're doing here, you could just use parameter expansion:

a=${msg%% *}; msg=${msg#* }
b=${msg%% *}; msg=${msg#* }
c=${msg%% *}; msg=${msg#* }

Upvotes: 7

Related Questions