为什么我在 Bash 条件中使用 NOT 运算符得到“找不到命令”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11197369/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why do I get "command not found" with the NOT operator in a Bash conditional?
提问by JuanPablo
if I have
如果我有
if [ ! -e $dir ];
then
mkdir $dir
fi
work, but not
工作,但不是
[[ ! -e $dir ]] || mkdir $dir
why ?
为什么 ?
Edit 0
编辑 0
with [[ ...I get
与[[ ...我得到
line 34: [[?!: command not found
Edit 1
编辑 1
bash --version
GNU bash, version 3.2.25(1)-release (i686-redhat-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.
Edit 2
编辑 2
in some case work and some case don't work, two consecutives commands
在某些情况下工作和某些情况下不起作用,两个连续的命令
[user@host ~]$ [ -e /tmp ]?&& date
-bash: [: missing `]'
[user@host ~]$ [ -e /tmp ] && date
mar jun 26 10:05:50 CLT 2012
采纳答案by Gordon Davisson
Especially after edit 2, this really looks to me like a problem with "funny" characters, either nonprinting characters getting mixed in, or normal-looking-but-weird characters like nonbreaking spaces. These can be fairly hard to detect; things can look completely normal in an editor, and even if you view a script with something like cat -vit won't always show funny characters clearly. If you have xxdon your system, it's a really good way to see precisely what's in the file. Here's a quick demo of this type of problem:
特别是在编辑 2 之后,这在我看来真的像是一个“有趣”字符的问题,要么是非打印字符混入,要么是看起来正常但奇怪的字符,比如不间断的空格。这些可能相当难以检测;事情在编辑器中看起来完全正常,即使您查看带有类似cat -v内容的脚本,也不总是清楚地显示有趣的角色。如果您xxd的系统上有,这是一种准确查看文件内容的好方法。这是此类问题的快速演示:
$ cat -v nbsptest
#!/bin/bash -x
[?-e /tmp ] && date
[ -e /tmp?] && date
[ -e /tmp ] && date
$ ./nbsptest
+ '[?-e' /tmp ']'
./nbsptest: line 2: [?-e: command not found
+ '[' -e '/tmp?]'
./nbsptest: line 3: [: missing `]'
+ '[' -e /tmp ']'
+ date
Sat Jun 30 10:53:56 PDT 2012
$ xxd nbsptest
0000000: 2321 2f62 696e 2f62 6173 6820 2d78 0a5b #!/bin/bash -x.[
0000010: c2a0 2d65 202f 746d 7020 5d20 2626 2064 ..-e /tmp ] && d
0000020: 6174 650a 5b20 2d65 202f 746d 70c2 a05d ate.[ -e /tmp..]
0000030: 2026 2620 6461 7465 0a5b 202d 6520 2f74 && date.[ -e /t
0000040: 6d70 205d 2026 2620 6461 7465 0a mp ] && date.
The script looks completely normal with cat -v(and more, vi, etc), but the first two commands fail. xxdshows why: the first command has a UTF-8 nonbreaking space between the [and the -e(this shows as c2a0 in the hex listing, [..-ein the text listing) and the second command has a nonbreaking space between /tmpand ](/tmp..]in the text listing).
脚本看起来完全正常cat -v(和more,vi等),但前两个命令失败。 xxd说明原因:第一个命令在[和之间有一个 UTF-8 不间断空格-e(在十六进制列表中,[..-e在文本列表中显示为 c2a0 ),第二个命令在/tmp和](/tmp..]在文本列表中)之间有一个不间断空格。
The -xdisplay (I used bash -xto invoke it, you can also use set -xas @CodeGnome suggested) also gives a hint about what's going on. For the first command, it listed it as '[?-e' /tmp ']'-- note the quotes around [ -e, which indicates that the shell is treating that all as one "word", which means it doesn't think that's a space in the middle of it. Similarly, the second command is displayed as '[' -e '/tmp ]'with the quotes indicating that it thinks /tmp ]is all one "word".
该-x显示器(我用bash -x调用它,你也可以使用set -x如@CodeGnome建议)也给出了关于这是怎么回事提示。对于第一个命令,它将它列为'[?-e' /tmp ']'-- 注意周围的引号[ -e,这表明 shell 将所有这些都视为一个“单词”,这意味着它不认为这是中间的空格。类似地,第二个命令显示为'[' -e '/tmp ]'带有引号,表明它认为/tmp ]是一个“单词”。
回答by redtuna
You should use
你应该使用
[ ! -e $dir ] && mkdir $dir
the single "[" is a shortcut for calling test, so the test syntax applies. The double "[[" instead uses bash's logic syntax, which is completely different.
单个“[”是调用测试的快捷方式,因此测试语法适用。双 "[[" 使用 bash 的逻辑语法,这是完全不同的。
And since you want to execute the command if the test returns true, you should use "&&" - the "||" syntax will only run your command if the test returns false.
并且由于您想在测试返回 true 时执行该命令,因此您应该使用“&&”-“||” 如果测试返回 false,语法将仅运行您的命令。
edit:
编辑:
checking the bash man page reveals that conditional expressions (what you get with [[) also understand the -e syntax. That section doesn't mention "!" for negating the result, though it works when trying it on the command line. My guess then is that your system may be running a different version of bash from that of the commenters, one that doesn't understand "!" ? The man page for test clearly indicates that "!" is supported, so in your shoes I would first try with [ ] and see if that works before exploring further.
检查 bash 手册页显示条件表达式(你用 [[] 得到的)也理解 -e 语法。该部分没有提到“!” 用于否定结果,尽管它在命令行上尝试时有效。我的猜测是,您的系统可能正在运行与评论者不同版本的 bash,一个不理解“!”的人。? 测试的手册页清楚地表明“!” 支持,所以在你的鞋子里,我会首先尝试使用 [ ] 并在进一步探索之前看看它是否有效。
回答by Todd A. Jacobs
The Syntax Works
语法作品
At least, it works for me. For example:
至少,它对我有用。例如:
# Inverted logic. Returns false because directory exists.
$ [[ ! -e /tmp ]]; echo $?
1
Are you sure you're using Bash? Check your shell and version.
你确定你在使用 Bash 吗?检查您的外壳和版本。
$ echo $SHELL $BASH_VERSION
/bin/bash 4.2.10(1)-release
A Better Approach
更好的方法
Your conditional logic is a bit convoluted. This is a much cleaner syntax for what you want to do:
你的条件逻辑有点复杂。对于您要执行的操作,这是一种更清晰的语法:
dir=/tmp/foo
[[ -e "$dir" ]] || mkdir "$dir"
This is semantically clearer, and expresses the intent without the inverted logic. There may be cases where you need an inverted test, but your example isn't one of them.
这在语义上更清晰,并且在没有反转逻辑的情况下表达意图。可能在某些情况下您需要倒置测试,但您的示例不是其中之一。

