bash 如何制作“如果不是真实条件”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10552711/
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-09 22:03:26  来源:igfitidea点击:

How to make "if not true condition"?

bashif-statementsyntaxboolean-expression

提问by Sandra Schlichting

I would like to have the echocommand executed when cat /etc/passwd | grep "sysa"is not true.

我希望echocat /etc/passwd | grep "sysa"不正确时执行命令。

What am I doing wrong?

我究竟做错了什么?

if ! [ $(cat /etc/passwd | grep "sysa") ]; then
        echo "ERROR - The user sysa could not be looked up"
        exit 2
fi

回答by shellter

try

尝试

if ! grep -q sysa /etc/passwd ; then

grepreturns trueif it finds the search target, and falseif it doesn't.

greptrue如果找到搜索目标,false则返回,否则返回。

So NOT false== true.

所以不是false== true

ifevaluation in shells are designed to be very flexible, and many times doesn't require chains of commands (as you have written).

ifshell 中的评估被设计为非常灵活,并且很多时候不需要命令链(如您所写)。

Also, looking at your code as is, your use of the $( ... )form of cmd-substitution is to be commended, but think about what is coming out of the process. Try echo $(cat /etc/passwd | grep "sysa")to see what I mean. You can take that further by using the -c(count) option to grep and then do if ! [ $(grep -c "sysa" /etc/passwd) -eq 0 ] ; thenwhich works but is rather old school.

此外,按原样查看您的代码,您$( ... )对 cmd-substitution 形式的使用值得称赞,但请考虑一下该过程会产生什么。试着echo $(cat /etc/passwd | grep "sysa")明白我的意思。您可以通过使用-c(count) 选项进行 grep来进一步实现if ! [ $(grep -c "sysa" /etc/passwd) -eq 0 ] ; then这一点,然后执行该操作,但这是相当老派的。

BUT, you could use the newest shell features (arithmetic evaluation) like

但是,您可以使用最新的 shell 功能(算术评估),例如

if ! (( $(grep -c "sysa" /etc/passwd) == 0 )) ; then ...`

which also gives you the benefit of using the c-lang based comparison operators, ==,<,>,>=,<=,%and maybe a few others.

这也为您提供了使用基于 c-lang 的比较运算符的好处,==,<,>,>=,<=,%也许还有其他一些。

In this case, per a comment by Orwellophile, the arithmetic evaluation can be pared down even further, like

在这种情况下,根据 Orwellophile 的评论,算术评估可以进一步缩减,例如

if ! (( $(grep -c "sysa" /etc/passwd) )) ; then ....

OR

或者

if (( ! $(grep -c "sysa" /etc/passwd) )) ; then ....

Finally, there is an awardcalled the Useless Use of Cat (UUOC). :-) Some people will jump up and down and cry gothca! I'll just say that grepcan take a file name on its cmd-line, so why invoke extra processes and pipe constructions when you don't have to? ;-)

最后,有一个奖项叫做Useless Use of Cat (UUOC)。:-) 有些人会跳上跳下哭着哥特卡!我只想说它grep可以在其 cmd 行上使用文件名,那么为什么在不需要时调用额外的进程和管道结构呢?;-)

I hope this helps.

我希望这有帮助。

回答by Rony

I think it can be simplified into:

我认为可以简化为:

grep sysa /etc/passwd || {
    echo "ERROR - The user sysa could not be looked up"
    exit 2
}

or in a single command line

或在单个命令行中

$ grep sysa /etc/passwd || { echo "ERROR - The user sysa could not be looked up"; exit 2; }

$ grep sysa /etc/passwd || { echo "ERROR - The user sysa could not be looked up"; exit 2; }

回答by phil294

What am I doing wrong?

我究竟做错了什么?

$(...)holds the value, not the exit status, that is why this approach is wrong. However, in this specific case, it does indeed work because sysawill be printed which makes the test statement come true. However, if ! [ $(true) ]; then echo false; fiwould always print falsebecause the truecommand does not write anything to stdout (even though the exit code is 0). That is why it needs to be rephrased to if ! grep ...; then.

$(...)持有价值,而不是退出状态,这就是为什么这种方法是错误的。但是,在这种特定情况下,它确实有效,因为sysa将打印使测试语句成真。但是,if ! [ $(true) ]; then echo false; fi总是会打印,false因为该true命令不会向 stdout 写入任何内容(即使退出代码为 0)。这就是为什么它需要改写为if ! grep ...; then.

An alternative would be cat /etc/passwd | grep "sysa" || echo error. Edit: As Alex pointed out, cat is useless here: grep "sysa" /etc/passwd || echo error.

另一种选择是cat /etc/passwd | grep "sysa" || echo error。编辑:正如亚历克斯指出的那样,猫在这里没用grep "sysa" /etc/passwd || echo error

Found the other answers rather confusing, hope this helps someone.

发现其他答案相当混乱,希望这对某人有所帮助。

回答by Kusalananda

On Unix systems that supports it (not macOS it seems):

在支持它的 Unix 系统上(似乎不是 macOS):

if getent passwd "$username" >/dev/null; then
    printf 'User %s exists\n' "$username"
else
    printf 'User %s does not exist\n' "$username"
fi 

This has the advantage that it will query any directory service that may be in use (YP/NIS or LDAP etc.) and the local password database file.

这样做的好处是它将查询可能正在使用的任何目录服务(YP/NIS 或 LDAP 等)和本地密码数据库文件。



The issue with grep -q "$username" /etc/passwdis that it will give a false positive when there is no such user, but something else matches the pattern. This could happen if there is a partial or exact match somewhere else in the file.

问题grep -q "$username" /etc/passwd在于,当没有这样的用户时,它会给出误报,但其他内容与模式匹配。如果文件中的其他地方有部分或完全匹配,就会发生这种情况。

For example, in my passwdfile, there is a line saying

例如,在我的passwd文件中,有一行说

build:*:21:21:base and xenocara build:/var/empty:/bin/ksh

This would provoke a valid match on things like caraand enocetc., even though there are no such users on my system.

这将引起人们对事物一样有效匹配caraenoc等,即使有我的系统上没有这样的用户。

For a grepsolution to be correct, you will need to properly parse the /etc/passwdfile:

为了使grep解决方案正确,您需要正确解析/etc/passwd文件:

if cut -d ':' -f 1 /etc/passwd | grep -qxF "$username"; then
    # found
else
    # not found
fi

... or any other similar test against the first of the :-delimited fields.

... 或针对第一个:-delimited 字段的任何其他类似测试。

回答by SDsolar

Here is an answer by way of example:

下面是一个例子的答案:

In order to make sure data loggers are online a cronscript runs every 15 minutes that looks like this:

为了确保数据记录器在线,cron脚本每 15 分钟运行一次,如下所示:

#!/bin/bash
#
if ! ping -c 1 SOLAR &>/dev/null
then
  echo "SUBJECT:  SOLAR is not responding to ping" | ssmtp [email protected]
  echo "SOLAR is not responding to ping" | ssmtp [email protected]
else
  echo "SOLAR is up"
fi
#
if ! ping -c 1 OUTSIDE &>/dev/null
then
  echo "SUBJECT:  OUTSIDE is not responding to ping" | ssmtp [email protected]
  echo "OUTSIDE is not responding to ping" | ssmtp [email protected]
else
  echo "OUTSIDE is up"
fi
#

...and so on for each data logger that you can see in the montage at http://www.SDsolarBlog.com/montage

...等等,您可以在http://www.SDsolarBlog.com/montage的蒙太奇中看到每个数据记录器



FYI, using &>/dev/nullredirects all output from the command, including errors, to /dev/null

仅供参考,使用&>/dev/null将命令的所有输出(包括错误)重定向到/dev/null

(The conditional only requires the exit statusof the pingcommand)

(该条件仅需要exit status所述的ping命令)

Also FYI, note that since cronjobs run as rootthere is no need to use sudo pingin a cronscript.

另外仅供参考,请注意,由于cron作业运行时root无需sudo pingcron脚本中使用。