Why does [:lower:] return differently in bash depending on the existence of files?

前端 未结 1 1050
-上瘾入骨i
-上瘾入骨i 2021-01-14 11:10

This just happened to me in bash:

$ echo HELLO|tr [:upper:] [:lower:]
hello
$ touch w
$ echo HELLO|tr [:upper:] [:lower:]
wwwww
$ echo [:upper:]
[:upper:]
$          


        
相关标签:
1条回答
  • 2021-01-14 11:32

    An expression like [:lower:] is a glob pattern if you don't enclose it in quotes. Thus, it matches a filename that is exactly one* of the characters in the square braces. What you probably want is to simply quote it:

    $ tr '[:upper:]' '[:lower:]' <<< ABC
    abc
    

    As hobbs points out in his comment, I should explain the inconsistency of why the behavior changes depending on if the file is present or not. If no file matching the glob exists, the behavior of bash is determined by whether or not the nullglob extension is enabled. It's disabled by default.

    If no matching file names are found, and the shell option nullglob is not enabled, the word is left unchanged.

    Thus, if no file with a name consisting entirely of one of ':', 'l', 'o', 'w', 'e', or 'r' exists, the glob [:lower:] will expand to the word [:lower:].

    *Updated. As Glenn Jackman points out in his comment, I had previously mistakenly confused [:lower:] for [[:lower:]]. It is confusing. In most places where you apply regular expressions in POSIX utilities and shell commands the character class itself has to be explicitly wrapped with square braces. So [a-z] is [[:lower:]] in the C locale, for example. But tr breaks the rules and implies the square braces, such that tr -d '[:lower:]' is equivalent to tr -d 'a-z' in the C locale. So my excuse is that when tr is involved I regularly forget how many braces are actually needed. :P

    0 讨论(0)
提交回复
热议问题