Arrays in Unix Bourne Shell
Solution 1
/bin/sh
is hardly ever a Bourne shell on any systems nowadays (even Solaris which was one of the last major system to include it has now switched to a POSIX sh for its /bin/sh in Solaris 11). /bin/sh
was the Thompson shell in the early 70s. The Bourne shell replaced it in Unix V7 in 1979.
/bin/sh
has been the Bourne shell for many years thereafter (or the Almquist shell, a free reimplementation on BSDs).
Nowadays, /bin/sh
is more commonly an interpreter or another for the POSIX sh
language which is itself based on a subset of the language of ksh88 (and a superset of the Bourne shell language with some incompatibilities).
The Bourne shell or the POSIX sh language specification don't support arrays. Or rather they have only one array: the positional parameters ($1
, $2
, $@
, so one array per function as well).
ksh88 did have arrays which you set with set -A
, but that didn't get specified in the POSIX sh as the syntax is awkward and not very usable.
Other shells with array/lists variables include: csh
/tcsh
, rc
, es
, bash
(which mostly copied the ksh syntax the ksh93 way), yash
, zsh
, fish
each with a different syntax (rc
the shell of the once to-be successor of Unix, fish
and zsh
being the most consistent ones)...
In standard sh
(also works in modern versions of the Bourne shell):
set '1st element' 2 3 # setting the array
set -- "$@" more # adding elements to the end of the array
shift 2 # removing elements (here 2) from the beginning of the array
printf '<%s>\n' "$@" # passing all the elements of the $@ array
# as arguments to a command
for i do # looping over the elements of the $@ array ($1, $2...)
printf 'Looping over "%s"\n' "$i"
done
printf '%s\n' "$1" # accessing individual element of the array.
# up to the 9th only with the Bourne shell though
# (only the Bourne shell), and note that you need
# the braces (as in "${10}") past the 9th in other
# shells (except zsh, when not in sh emulation and
# most ash-based shells).
printf '%s\n' "$# elements in the array"
printf '%s\n' "$*" # join the elements of the array with the
# first character (byte in some implementations)
# of $IFS (not in the Bourne shell where it's on
# space instead regardless of the value of $IFS)
(note that in the Bourne shell and ksh88, $IFS
must contain the space character for "$@"
to work properly (a bug), and in the Bourne shell, you can't access elements above $9
(${10}
won't work, you can still do shift 1; echo "$9"
or loop over them)).
Solution 2
As the others have said, the Bourne Shell doesn't have true arrays.
However, depending on what you need to do, delimited strings should suffice:
sentence="I don't need arrays because I can use delimited strings"
for word in $sentence
do
printf '%s\n' "$word"
done
If the typical delimiters (space, tab, and newline) don't suffice, you can set IFS
to whatever delimiter you want before the loop.
And if you need to build the array programmatically, you can just build up a delimited string.
Solution 3
There are no arrays in plain Bourne shell. You can use the following way to create an array and traverse it:
#!/bin/sh
# ARRAY.sh: example usage of arrays in Bourne Shell
array_traverse()
{
for i in $(seq 1 $2)
do
current_value=$1$i
echo $(eval echo \$$current_value)
done
return 1
}
ARRAY_1=one
ARRAY_2=two
ARRAY_3=333
array_traverse ARRAY_ 3
No matter what way to use arrays in sh
would you pick it will always be cumbersome. Consider using a different language such as Python
or Perl
if you can unless you are stuck with a very limited platform or want to learn something.
Related videos on Youtube
![SubhasisM](https://i.stack.imgur.com/nzxYh.jpg?s=256&g=1)
SubhasisM
Updated on September 18, 2022Comments
-
SubhasisM almost 2 years
I am trying to use arrays in Bourne shell (
/bin/sh
). I found that the way to initialize array elements is:arr=(1 2 3)
But it is encountering an error:
syntax error at line 8: `arr=' unexpected
Now the post where I found this syntax says it is for
bash
, but I could not find any separate syntax for Bourne shell. Does the syntax stand the same for/bin/sh
as well?-
SubhasisM about 10 yearsThnx @Nischay...After reading the link you provided, I refined my query string in google and got the link -docstore.mik.ua/orelly/unix/upt/ch45_34.htm
-
-
Stéphane Chazelas about 10 years@NoobGeek, the Bourne shell doesn't have the
$(...)
syntax. So you must indeed have the Bourne shell. Are you on Solaris 10 or before? Chances are you won't have aseq
either. On Solaris 10 and earlier, you want /usr/xpg4/bin/sh to have a standardsh
instead of a Bourne shell. Usingseq
that way is not very good either. -
Arkadiusz Drabczyk about 10 yearsPOSIX states that $ and ` are equivalent in command substitution: link. And why is using of
seq
that way not good? -
SubhasisM about 10 years@Stéphane Chazelas: Actually I am using '$' in some other script and that is working properly (var3=
expr $var1 + $var2
). -
Stéphane Chazelas about 10 yearsYes in POSIX shells, you should prefer
$(...)
over`
, but the OP's/bin/sh
is probably a Bourne shell, not a POSIX shell. Besideseq
not being a standard command, doing$(seq 100)
means storing the whole output in memory, and that means it depends on the current value of $IFS containing newline and not containing digits. Best to usei=1; while [ "$i" -le 100 ]; ...; i=$(($i + 1)); done
(though that wouldn't work in the Bourne shell either). -
Daenyth about 10 yearsIf you are learning shell scripting you almost certainly learn bash rather than sh. You'll (probably) never need sh, and learning that first will give you terrible habits when you do learn bash
-
Stéphane Chazelas about 9 yearsUnless you do want it (unlikely), you'll probably also want to disable globbing which is another effect of leaving variables unquoted like that (the
split+glob
operator). -
Josip Rodin over 8 years@Daenyth I would say quite the contrary: learning bashisms first, and then portable
/bin/sh
syntax later, tends to make people think it's okay to use the wrong#!/bin/sh
shebang, and then breaks their scripts when other people try to use them. You'd be well advised to not post this kind of flamebait. :) -
ssola over 8 yearsIt may be worth noting that positional parameters differ from bash arrays in some key features. For example, they do not support sparse arrays, and since sh doesn't have slicing parameter expansion, you can't access sublists like
"${@:2:4}"
. To be sure, I see the similarities, but I don't regard positional parameters as an array per se. -
Stéphane Chazelas over 6 years@kojiro, to some extent, I'd say it's the contrary,
"$@"
acts like an array (like the arrays ofcsh
,rc
,zsh
,fish
,yash
...), it's more the Korn/bash "arrays" that are not really arrays, but some form of associative arrays with keys limited to positive integers (they also have indices starting at 0 instead of 1 like in all other shells with arrays and "$@"). Shells that have support for slicing can slice $@ just the same (with ksh93/bash awkwardly adding $0 to the positional parameters when you slice "$@"). -
Sridhar Sarnobat almost 3 years
/bin/sh
continues to give meSyntax error: "(" unexpected
for arrays