如何使“如果不是真实条件”?


317

我想echocat /etc/passwd | grep "sysa"不正确的时候执行命令。

我究竟做错了什么?

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

7
如若!不是括号内?即[ ! EXPR ]
acraig5075

7
@ acraig5075这两种方法都是有效的,但是此语句中根本不需要测试命令(即括号)。
查尔斯·达菲

Answers:


454

尝试

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

grep返回true是否找到搜索目标,false否则返回。

所以不false== true

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

同样,以原样看待您的代码,使用$( ... )cmd-substitution 的形式值得赞赏,但是请考虑一下过程中会出现什么。尝试echo $(cat /etc/passwd | grep "sysa")明白我的意思。您可以通过使用-c(count)选项对grep进行进一步处理,然后再做if ! [ $(grep -c "sysa" /etc/passwd) -eq 0 ] ; then一些可行的工作,但这是相当古老的做法。

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

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

这也使您受益于使用基于c-lang的比较运算符,==,<,>,>=,<=,%也许还有其他一些。

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

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

要么

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

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

我希望这有帮助。


1
从我的答案到更困难的(问题)[ stackoverflow.com/a/30400327/912236], grep "^$user:" /etc/passwd这真的是很愚蠢的,它是偶然搜索/ etc / passwd的更正确方法– 如果需要grep -v-v会反转搜索避免||的混乱
Orwellophile 2015年

1
是的,嗯,最有效地解决了一个问题,然后回答了特定的问题。我试图回答具体问题。感谢您的想法。祝你们好运。
剥壳机

1
不选择您的答案,非常喜欢。我只是通过我会在用户名上进行适当范围的检查,否则,如果OP确实确实在“ sys”或类似名称上进行搜索,他会感到非常惊讶。再上一条路? (( $( cat file | grep regex | wc -l ) ? 0 : 1 ))
Orwellophile 2015年

1
大!由于某种原因,reqular“!grep -qs ...”无法与/ proc / mounts一起使用,并试图确定Raspbian 4.9内核上是否安装了定期掉落的USB磁盘。这一位做得很好!
DocWeird,

33

我认为可以简化为:

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; }


4
很好,但是我更喜欢Shellter先生的回答,因为它是“自我记录”的,更容易理解程序员的意图。
0zkrPM

1
我喜欢这个版本。1>&2在您的末尾添加echo打印内容会stderr如何?
朱利安

2
@ 0zkrPM但是shellster版本在Bourne shell中不起作用。您将获得!: not found
ceving 2013年

1
'grep像这样使用时,请避免输出重定向。-q抑制输出。
tbc0

8

我究竟做错了什么?

$(...)保留,而不是退出状态,这就是这种方法错误的原因。但是,在这种特定情况下,它确实可以工作,因为sysa它将被打印出来,从而使测试语句成为现实。但是,if ! [ $(true) ]; then echo false; fi将始终打印,false因为该true命令不会向stdout写入任何内容(即使退出代码为0)。这就是为什么需要将其改为if ! grep ...; then

一个替代方案是cat /etc/passwd | grep "sysa" || echo error。编辑:正如亚历克斯指出,猫在这里是无用的grep "sysa" /etc/passwd || echo error

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


1

在支持它的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 

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


问题grep -q "$username" /etc/passwd在于,当没有这样的用户时,它将给出一个误报,但其他人会匹配该模式。如果文件中其他位置存在部分或完全匹配,则可能会发生这种情况。

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

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

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

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

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

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


@SDsolar bash在这种情况下,您的代码可能未被执行。
库萨兰达

1

这是一个示例答案:

为了确保数据记录器处于联机状态,cron脚本每15分钟运行一次,如下所示:

#!/bin/bash
#
if ! ping -c 1 SOLAR &>/dev/null
then
  echo "SUBJECT:  SOLAR is not responding to ping" | ssmtp abc@def.com
  echo "SOLAR is not responding to ping" | ssmtp 4151112222@txt.att.com
else
  echo "SOLAR is up"
fi
#
if ! ping -c 1 OUTSIDE &>/dev/null
then
  echo "SUBJECT:  OUTSIDE is not responding to ping" | ssmtp abc@def.com
  echo "OUTSIDE is not responding to ping" | ssmtp 4151112222@txt.att.com
else
  echo "OUTSIDE is up"
fi
#

...等等,您可以在http://www.SDsolarBlog.com/montage的剪辑画面中看到的每个数据记录器


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

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

另外请注意,由于cron作业按原样运行,root因此无需sudo pingcron脚本中使用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.