this is a bash 4 specific question. I am somewhat familiar with the bash Brace Expressions and I have read the manual but I do not understand how it actually works.

I guess it has to do with the ASCII table but I am not used to searching the bash source code to confirm it so my question is this:

Why does this echo {G..a} expand to

G H I J K L M N O P Q R S T U V W X Y Z [  ] ^ _ ` a
  • It does not have to be the ASCII table. It depends on your locale. Mar 20 '19 at 10:50
  • I guess each charset uses a different ASCII table. My guess is that there is a loop somewhere in the code. The start and end delimiters are encoded in hex or dec and each element is printed with it's printable counterpart. With a different locale I guess one can indeed expect different results. Does this make the brace expressions not portable, even when bash 4 is guaranteed to be used? Mar 20 '19 at 10:55
  • 1
    Yeah you are right, if you run echo {G..a} you will get the output I mentioned. I will edit my question, which still remains though. Mar 20 '19 at 11:19
  • 2
    See also lists.gnu.org/archive/html/bug-bash/2015-07/msg00135.html (which explains the missing backslash) Mar 20 '19 at 12:02
  • 1
    ASCII is a charset; if you have a different character set than ASCII, then ASCII tables don't apply.
    – chepner
    Mar 20 '19 at 13:34

From the bash manual (with my emphasis):

A sequence expression takes the form {x..y[..incr]}, where x and y are either integers or single characters, and incr, an optional increment, is an integer. When integers are supplied, the expression expands to each number between x and y, inclusive. Supplied integers may be prefixed with 0 to force each term to have the same width. When either x or y begins with a zero, the shell attempts to force all generated terms to contain the same number of digits, zero-padding where necessary. When characters are supplied, the expression expands to each character lexicographically between x and y, inclusive, using the default C locale. Note that both x and y must be of the same type. When the increment is supplied, it is used as the difference between each term. The default increment is 1 or -1 as appropriate.

Brace expansions with letters as ranges allows for mixed-case ranges in bash. So what you are seeing are the characters between G and a in the ASCII table (with a default 1 increment as the values occur in that order in the table).

Between the last uppercase character (Z) and the first lowercase character (a) in the standard ASCII table, there are the characters

[ \ ] ^ _ `

in this order.

You do not get \ in your output as the shell would treat an escaped space character as a literal space. Also note that since an unquoted backtick is outputted, this could potentially lead to unexpected code execution, as pointed out by Stéphane in a message to the bug-bash mailing list in 2015.

I do however not quite know what the manual refers to as "type", but my guess would be that you can't use a letter and a digit, as in {1..z} (which indeed does not expand).


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.