为什么我在 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 02:36:07  来源:igfitidea点击:

Why do I get "command not found" with the NOT operator in a Bash conditional?

bashif-statement

提问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(和morevi等),但前两个命令失败。 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.

这在语义上更清晰,并且在没有反转逻辑的情况下表达意图。可能在某些情况下您需要倒置测试,但您的示例不是其中之一。