7

I'm currently learning the command line and I'm learning Positional Parameters. And I saw that the Positional Parameters end at nine, To use more than $9, I must put them in curly braces, like: ${18}. But what is the story of the nine Positional Parameters and not allowed to put more of them in shape:$18?

4
  • 18
    $18 is understood as ${1}8. I guess the lexer is simpler like this. Dec 12, 2021 at 19:40
  • 26
    technically, your opening statement is misleading, you say there's only nine positional parameters, yet you show that there is no limit of 9
    – Bravo
    Dec 12, 2021 at 21:31
  • 8
    I would be very surprised if the story was anything other than that it was done like that in the first implementation and it stuck due to backward compatibility.
    – ilkkachu
    Dec 12, 2021 at 21:58
  • 2
    I find it's helpful if you view ${var} as the "official" way to expand shell variables, and think of dropping the curly braces as a shortcut which is enabled in some, but not all, cases.
    – R.M.
    Dec 14, 2021 at 13:22

1 Answer 1

29

The list of positional parameters can be as long as required and as current resource limits allows. This means that there may be well over 9 elements in the list. As you have already noticed, elements 10 and later may be accessed by adding braces around the number, as in ${12}.

The reason the braces are needed to access elements beyond element 9 in most POSIX-like shells is because the POSIX standard says so.

A positional parameter is a parameter denoted by the decimal value represented by one or more digits, other than the single digit 0. The digits denoting the positional parameters shall always be interpreted as a decimal value, even if there is a leading zero. When a positional parameter with more than one digit is specified, the application shall enclose the digits in braces.

(From here, "Shell Command Language: Positional Parameters")

The word "application" in the text above means "your script".

The simplest form for parameter expansion is:

${parameter}

The value, if any, of parameter shall be substituted.

The parameter name or symbol can be enclosed in braces, which are optional except for positional parameters with more than one digit or when parameter is a name and is followed by a character that could be interpreted as part of the name.

(From here, "Shell Command Language: Parameter Expansion")

Note also that addressing any other than the first few positional parameters directly is quite a rare thing to do. It's common to access $1 and $2, but $3 and the others see very little use. It's more common to iterate over the list, as in

for argument do
    # use "$argument" here
done

... or to use the whole list at once with "$@".

Also note that some shells may choose to ignore the standard. Here's the zsh shell, which does not try to be strictly POSIX compliant:

$ set -- a b c d e f g h i j k l m n o p
$ print $13
m
$ print $16
p

... unless it's emulating sh:

$ emulate sh
$ print $13
a3

The a3 string comes from outputting $1 followed by 3.

2
  • 6
    In the Bourne shell, ${10} won't work and $10 is ${1}0 likely like that for compatibility with the Thompson shell. POSIX most likely specifies it like that because it's how it's done in ksh (which does it like that for Bourne compatibility, though allows ${10} as an extension). Dec 13, 2021 at 17:20
  • 1
    Not every reader here may be aware that Bourne, referenced in the above comment, is much older than currently-common /bin/sh implementations -- such as ash and dash -- which are compliant with the early-1990s POSIX.2 standard, which Bourne predates by decades. Dec 14, 2021 at 17:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .