对于字符t和值root,会发生这种情况.相当令人困惑
$ echo [s]
[s]
$ echo [t]
t
$ echo [ t ]
[ t ]
$ echo [root]
t
Run Code Online (Sandbox Code Playgroud)
dev*_*ull 62
[]表示一个字符类,并且您有一个t在当前目录中命名的文件.
以下内容应进一步解释:
$ ls
$ echo [t]
[t]
$ touch t
$ echo [t]
t
$ echo [root]
t
$ touch r
$ echo [root]
r t
Run Code Online (Sandbox Code Playgroud)
如果你想回应内在的东西[],逃避[:
echo \[$var]
Run Code Online (Sandbox Code Playgroud)
现在观察差异:
$ echo \[root]
[root]
Run Code Online (Sandbox Code Playgroud)
或者,正如格伦杰克曼指出的那样,引用它:
$ echo '[root]'
[root]
$ echo "[root]"
[root]
Run Code Online (Sandbox Code Playgroud)
Shell命令语言告诉shell,以下字符是特殊的,具体取决于上下文:
* ? [ # ~ = %
Run Code Online (Sandbox Code Playgroud)
此外,如果要表示自己,必须引用以下字符:
| & ; < > ( ) $ ` \ " ' <space> <tab> <newline>
Run Code Online (Sandbox Code Playgroud)
如果您没有引用参数,也可以使用它printf来确定给定输入中的哪些字符需要转义.对于你的例子,即[s]:
$ printf "%q" "[s]"
\[s\]
Run Code Online (Sandbox Code Playgroud)
另一个例子:
$ printf "%q" "[0-9]|[a-z]|.*?$|1<2>3|(foo)"
\[0-9\]\|\[a-z\]\|.\*\?\$\|1\<2\>3\|\(foo\)
Run Code Online (Sandbox Code Playgroud)
Ama*_*ali 26
[]表示一个字符类.简单地说,字符类是一种表示一组字符的方式,使得该集合中的一个字符匹配.[A-Z]是一种很常见的例子-它所有的字母从匹配A通过Z.
以下是新目录中命令的结果:
$ echo [s]
[s]
$ echo [t]
[t]
$ echo [ t ]
[ t ]
$ echo [root]
[root]
Run Code Online (Sandbox Code Playgroud)
如您所见,echo按原样显示它们.为什么?阅读下一节.
每次在终端上键入命令并按ENTER键时,bash会在将结果打印到shell之前在内部执行大量操作.最简单的例子是扩展*:
$ echo *
evil_plans.txt dir1 dir2
Run Code Online (Sandbox Code Playgroud)
*它不打印文字作为输出,而是打印目录的内容.为什么会这样?因为*它具有特殊含义 - 它是一个通配符,可以匹配文件名的任何字符.重要的是要注意该echo命令实际上根本没有看到*- 只有扩展的结果.
有不同种类的扩展:
......可能还有更多.在这种情况下,文件名扩展是相关的扩展类型.
当您键入echo命令并按ENTER键时,bash会处理该命令并将其拆分为单词.一旦做到这一点,它会扫描字以下字符:?,*和[.所有这些都是元字符,具有特殊含义.如果bash发现这些字符中的任何一个出现,它会将提供的单词视为模式.
例如,请考虑以下情况:
$ touch foobar foobak fooqux barbar boofar
$ echo foo*
foobar foobak fooqux
Run Code Online (Sandbox Code Playgroud)
如您所见,*扩展并列出了匹配的文件名.(在这种情况下,那些以foo.开头的.)
现在让我们尝试另一个例子:
$ touch gray.txt grey.txt
$ echo gr?y.txt
gray.txt grey.txt
Run Code Online (Sandbox Code Playgroud)
?匹配单个字符.而已.在这种情况下,gray.txt与grey.txt两个匹配的模式,所以两者都打印出来.
另一个例子:
$ touch hello hullo hallo
$ echo h[aeu]llo
hallo hello hullo
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?如你所知,[aeu]是一个角色类.字符类恰好匹配其中的一个字符; 它永远不会匹配多个角色.在这种情况下,字符类中的字符可以正确匹配文件名,因此打印出结果.
如果找不到匹配的文件名,则该字保持不变.
$ echo [s]
Run Code Online (Sandbox Code Playgroud)
[s]是一个字符类,它只匹配一个字符 - 一个文字s.但是没有找到匹配的文件,所以它按原样返回.
$ echo [t]
Run Code Online (Sandbox Code Playgroud)
[t]也是一个角色类.它匹配一个单个字符.t您的目录中有一个文件,意思是匹配.所以它返回了找到的文件名的名称.
$ echo [root]
Run Code Online (Sandbox Code Playgroud)
[root]符合下列字符:r,o,t.正如你可能猜到的那样,o在角色类中出现两次并没有什么不同.字符类只能匹配单个字符.因此,echo [root]将尝试查找具有匹配字符的文件名.由于t您的目录中存在一个名为的文件,因此将其列出.
始终在需要时使用引用和转义.它们可以让您全面控制解析,扩展和扩展的结果.
Raf*_*ele 14
由于不是shell习惯(并且不愿意成为),我发现文件名扩展在未找到匹配项时的行为方式令人惊讶.我将报告Bash参考
猛砸扫描字符每个字
*,?和[.如果出现其中一个字符,则该单词被视为模式,并替换为与该模式匹配的按字母顺序排列的文件名列表.如果找不到匹配的文件名:
- 如果
nullglob禁用shell选项,则该字保持不变- 如果
nullglob设置了shell选项,则删除该单词- 如果
failglob设置了shell选项,则会打印一条错误消息,并且不会执行该命令
好消息是这个东西是可配置的.糟糕的是脚本可以通过多种方式失败 - 至少,我没有,并且我花了一些时间来理解为什么echo表现出你发布的方式,只是为了发现它是因为组合奇怪的文件名(谁想要命名文件t?),隐藏配置(nullglob禁用,默认选项但仍然隐藏)和无害命令.
我说无害,因为这是你得到的,例如,当目标是ls(由于找不到文件而失败):
raffaele@Aldebaran:~$ mkdir test
raffaele@Aldebaran:~$ cd test
raffaele@Aldebaran:~/test$ touch t
raffaele@Aldebaran:~/test$ ls [t]
t
raffaele@Aldebaran:~/test$ ls [v]
ls: cannot access [v]: No such file or directory
Run Code Online (Sandbox Code Playgroud)
补充devnull的有用答案:
在bash中使用不带引号的字符串(在大多数情况下)会导致它被解释为模式(通配符表达式;松散地说,是正则表达式的远程,原始相对).
在你的情况下,该模式对文件和子文件夹的名称在当前工作文件夹匹配,如@devnull证明:[root]是指:匹配名称只包含1个字符是任何文件或者 r 或 o(指定o两次是多余的)或 t.模式与文件名的匹配称为路径名扩展.
请注意,它也适用于不带引号的变量引用,因此以下结果将产生相同的结果:
s='[t]' # Assign string _literal_ (since quoted) to variable.
echo $s # Content of $s, since unquoted, is now subject to pathname expansion.
Run Code Online (Sandbox Code Playgroud)
要按字面意思处理字符串,必须使用引号.
使用您的示例有三种引用字符串的方法bash:
\- 引用具有特殊含义的单个字符(所谓的元字符):
echo \[t\]
这可确保将这些特殊字符视为文字.
将字符串括在单引号('...')中:
echo '[t]'
这可以保护字符串免受shell的任何扩展(解释).
警告:你不能将'自己包含在单引号字符串中(甚至不能转义).
将字符串括在双引号("...")中:
echo "[t]"
这可以保护字符串免受shell的某些扩展,同时有选择地允许其他人.
在手的情况下,'[t]'和"[t]"相同的行为.
但是,使用"允许您引用变量(参数扩展),执行命令替换以及
在字符串内执行计算(算术扩展),例如:
echo "Home, sweet $HOME." # reference to variable $HOME; parameter expansion
echo "Today's date and the current time are: $(date)" # command substitution
echo "Let's put $(( 2 + 2 )) together." # arithmetic expansion
对于所有扩展列表由执行bash,搜索部分EXPANSION在man bash或访问https://www.gnu.org/software/bash/manual/html_node/Shell-Expansions.html.