42

I was reading about positional parameters in Unix and then I found this info:

The shell allows a command line to contain at least 128 arguments; however, a shell program is restricted to referencing only nine positional parameters, $1 through $9, at a given time. You can work around this restriction by using the shift command.

So I created a simple shell script called file like the following:

#! /bin/bash
echo $14

then ran it like the following :

./file 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

and I got 14!

So how is that possible if the shell doesn't allow more than 10 parameters (from $0 to $9) without using shift command?

muru
  • 72,889

1 Answers1

69

When you run

echo $14

what happens is that bash interprets the argument $14 as $1 and 4 separately. It then expands $1 (which in this case is equal to "1"), then appends the string 4 to it, which results in "14". Although that was the result you were expecting, it's actually a side effect from Bash's actual behaviour. Like @steeldriver mentioned in comments, running your script like this instead :

./file a b c d e f g h i j k l m n

and then calling echo $14 won't output "n" but "a4".

Note that wrapping the variable in double-quotes :

echo "$14"

will still not expand the variable correctly in Bash. The standard method is to use curly braces around the variable name :

echo ${14}

For more information, see the official documentation for parameter expansion in Bash. It can do a lot more cool things too, like

${14^^*}

to capitalize argument no.14. Give it a read! :)

Umlin
  • 658
  • 9
    Note that that "bug" (unfortunately mandated by POSIX) where $14 is ${1}4 instead of ${14} was fixed in csh, ash, tcsh, rc, es, akanga and zsh (when not in sh/ksh emulation), though broken again in some ash derivatives for POSIX compliance. – Stéphane Chazelas Jan 25 '21 at 09:35
  • 2
    Just wrapping the variabled in double quotes does not work: bash -c 'echo "$14"' - WTF => WTF4. –  Jan 25 '21 at 09:59
  • 3
    If that worked for you, it's because you had used dash (Debian's /bin/sh) where simply echo $14 would've worked too: dash -c 'echo $14' - a b c d e f g h i j k l m n => n. –  Jan 25 '21 at 10:01
  • @user414777 Indeed. I used bash but I didn't test it properly. Thanks for pointing this out, I'll edit my answer. – Umlin Jan 25 '21 at 10:10
  • @user414777, fwiw, that seems to be fixed in newer versions of Dash – ilkkachu Jan 25 '21 at 10:54
  • 4
    @ilkkachu, fixed or broken depending on how you want to look at it. As per my first comment here, it used to be fine but was broken (IMO) in newer versions for POSIX compliance. – Stéphane Chazelas Jan 25 '21 at 14:32
  • 2
    @StéphaneChazelas, well. As far as I understand, Dash is meant to implement the POSIX shell language as it is, instead of creating a new but actually sane language. So in that context, behaviour that's both noncompliant and different from almost all other POSIX-like shells seems unquestionably a bug. – ilkkachu Jan 25 '21 at 22:33