0

I found the followings and want to know where I can find the manual:

❯ echo ${#}
1

❯ echo ${##}
1

❯ echo ${?}
0

❯ echo ${??}
0

❯ echo ${!}
0

❯ echo ${-}
569JNORXZghiklms

❯ echo ${--}
569JNORXZghiklms
1
  • 3
    Your question is tagged bash, but the output you are showing seems to come from zsh. Is zsh the shell you are actually using? – fra-san Feb 10 at 11:27
10

In about two different places, at least in Bash's manual. These should be standard features, and similar in each shell even if the actual value of ${-} here looks like it's from Zsh.

$ echo ${#}
1
$ echo ${?}
0
$ echo ${!}
0
$ echo ${-}
569JNORXZghiklms

These are the special parameters #, ?, !, and -, expanded with the optional braces. Using $#, $?, $! or $- would be the same. There are some other special parameters with single non-letter non-digit characters as their "name" and in general, ${foo} is the same as $foo but the braces are needed in a case like ${foo}bar, since $foobar would be taken as ${foobar}.

In particular,

  • $# is the number of positional parameters or arguments to the script or current function. Try fun() { echo $#; }; fun a b c;.

  • $? is the exit status of the last foreground command or pipeline (ls -l /doesnotexist; echo $?).

  • $! the process id if the latest background job (sleep 2 & ps uax |grep $!), and

  • $- the list of set flags in effect. (And some setopt flags in Zsh. Zsh also seems to give $! as 0 if there is no such job, Bash shows it as unset.)

$ echo ${##}
1
$ echo ${??}
0
$ echo ${--}
569JNORXZghiklms

These are the special parameters #, ?, and -, but with additional parameter expansion operations included. (I don't know what to call them, they're just part of parameter expansion.)

  • ${#parameter} is the length of the value of parameter, so when $# is 1 (or 0 etc.), ${##} is 1, and with foo=abc, ${#foo} is 3.

    (Somewhat related, ${parameter#word} removes a prefix, it would be the value of parameter with the leading part matching word removed (e.g. foo=abcdef; echo ${foo#??} gives cdef since ? matches any one character). The particular case of ${##} could be interpreted as either taking the length, or removing an empty prefix, but the length expansion trumps here. ${parameter%word} is the same but it removes a trailing part instead.)

  • ${parameter?word} is a "check if set" expansion, it gives the value of parameter if it's set, and otherwise throws an error with the text given by word. $? is always set, so the check doesn't do much, but try unset foo; echo ${foo?unset value\!}.

  • ${parameter-word} is a "default value" expansion, it takes the value of parameter if it is set, and otherwise word. $- is always set, so you get the value it has. But if foo is not set, ${foo-bar} would be bar.

The last two and other similar ones have variants with a colon, ${parameter:?word} and ${parameter:?word}, which also trigger when parameter is set to the empty string. Bash's manual could be clearer here, it mentions the difference in the text, but doesn't list the forms without a colon. The POSIX text has a nice table, though.


The fact that #, ? and - have two different meanings here is just a coincidence, or a consequence of having a limited set of special characters and the shell using a rather terse syntax for the uses.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.