AWK如何取代IF?

and*_*sg3 2 linux bash awk gawk

我正在审查其他人在工作中编写的一些bash脚本,我发现这条线我正在努力理解

[[ $(awk 'BEGIN{print ('$CAPACITY'>=0.9)}') -eq 1 ]] && echo "Capacity at 90 Percent"
Run Code Online (Sandbox Code Playgroud)

我的理解是这一行正在取代if语句.有人可以帮我解释一下这条线的真正作用.谢谢

Dav*_* W. 5

这让我对文明的未来感到非常悲伤和悲观......

让我们打破这个:

[[ $(awk 'BEGIN{print ('$CAPACITY'>=0.9)}') -eq 1 ]] && echo "Capacity at 90 Percent"
Run Code Online (Sandbox Code Playgroud)

请注意$(....).这告诉shell在里面执行程序,并用$(...)值替换内容.例如:

$ file_name="/usr/local/bin/foo"
$ short_name="$(basename $file_name)"
$ echo $short_name
foo
Run Code Online (Sandbox Code Playgroud)

在第二行中,我们正在运行命令basename $file_name.这回来了foo.然后,shell将替换foo$(basename $filename)分配之前short_name.以下是调试器的相同内容:

$ set -xv
$ file_name="/usr/local/bin/foo"
foo=/usr/local/bin/foo
+ foo=/usr/local/bin/foo
$ short_name=$(basename $file_name)
short_name=$(basename $file_name)
basename $file_name
++ basename /usr/local/bin/foo
+ short_name=foo
$ echo $short_name
echo $short_name
+ echo foo
foo
$ set +xv   # Turn off the debugger.
Run Code Online (Sandbox Code Playgroud)

您可以看到shell如何执行$(...)并替换它.

因此,用户实际上正在运行该程序:

awk 'BEGIN{print ('$CAPACITY'>=0.9)}'
Run Code Online (Sandbox Code Playgroud)

但是,看看引号:

awk 'BEGIN{print ('$CAPACITY'>=0.9)}'
     +++++++++++++           +++++++
Run Code Online (Sandbox Code Playgroud)

带有加号的东西是awk单引号内命令的一部分,因此不能由shell进行插值.但是,$CAPACITY不是在引号中.换句话说,在执行命令$CAPACITY之前替换该变量的值awk.因此,如果$CAPACITY是.8,awk命令将变为:

awk 'BEGIN{print ('.8'>=0.9)}`
Run Code Online (Sandbox Code Playgroud)

这是解释的第一部分.

现在进入下一部分.你知道awk多少?

Awk是一种编程语言,通常是Unix/Linux发行版的一部分.awk通常在文件上工作,并假定在文件周围循环,每行都被读入并操作.例如:

$ awk '{print $1}` foo.txt
Run Code Online (Sandbox Code Playgroud)

让我们假设每行foo.txt包含几个由空格分隔的字段.foo.txt读入文件并将每行传递给awk程序,awk程序将打印出每行的第一个字段.

但是,没有awk要操作的文件.这个开发人员正在使用特殊模式BEGIN.这是在读入任何行之前执行的.由于没有awk要处理的文件,并且没有实际awk程序(只有BEGIN语句),因此awk将执行此语句(假设容量为80%:

.8 >= .9
Run Code Online (Sandbox Code Playgroud)

就像在Shell和其他编程语言中一样.此声明将评估为真或假.在awk,如果这个陈述是真的,它将是一个非零值(我们希望1).如果是假,它将等于零.在这种情况下,它将等于假.

Awk返回(如Perl)它执行的最后一个值.因此,如果容量为80%,则该awk语句.8 >= .9将为false.Awk将返回零.

现在,整个$([[ $(awk 'BEGIN{print ('$CAPACITY'>=0.9)}')将被替换0.您的[[ ... ]]测试现在变为:

[[0 -eq 1]] && echo"容量为90%"

好吧,[[ 0 -eq 1 ]]是假的.

现在是最后一部分.

这两个命令 &&,并||在列表操作.他们的名字来自同名的C编程操作符,以及C短路测试的方式.例如,

if ( ( bar > 20 ) && ( foo < 30 ) ) {
Run Code Online (Sandbox Code Playgroud)

是典型的C if语句.以foobar为变量.我问的是bar是否大于20 并且如果foo小于30则执行某些操作.

C将首先评估bar > 20并判断它是真还是假.如果bar > 20为false,则无需测试,foo < 30因为无论结果如何,该语句仍然是错误的.如果bar确实大于20怎么办?您必须运行该if语句的下一部分.

想象一下:

if ( ( bar > 20 ) || ( foo < 30 ) ) {
Run Code Online (Sandbox Code Playgroud)

这表示如果bar大于20 OR foo <30.在这种情况下,C将评估是否bar大于20.如果是,则无需测试是否foo小于30.无论是什么语句都是真的价值foo是.如果bar不超过20怎么办?然后,我必须测试它的价值foo.

所以,如果我有,&&并且第一个语句是假的,不要做第二个语句(整个表达式无论如何都是假的).如果第一个语句为真,我必须运行第二个语句(因为我不知道整个语句是否为真).

如果我有||,完全相反的情况发生.如果第一个语句为true,则不要执行第二个语句(因为整个表达式为true).如果第一个语句为false,我必须运行第二个语句.

这个要点是:

[ "$foo" = "$bar" ] && echo "Foo equals bar"
Run Code Online (Sandbox Code Playgroud)

是相同的:

if [ "$foo" = "$bar" ]
then
    echo "Foo equals bar"
fi
Run Code Online (Sandbox Code Playgroud)

因为如果$foo相等$bar,我必须执行声明的第二部分!

还有这个:

[ "$foo" = "$bar" ] || echo "Foo and Bar are not equal"
Run Code Online (Sandbox Code Playgroud)

是相同的:

if [ "$foo" != "$bar" ]
then
    echo "Foo and Bar are not equal"
fi
Run Code Online (Sandbox Code Playgroud)
  1. 因此,首先shell将shell变量的值替换$CAPACITY为您的小awk脚本.
  2. 接下来,awk脚本运行测试替换值$CAPACITY是否大于或等于0.9.由于没有实际awk程序,因此awk不会尝试从STDIN读入.
  3. 接下来,awk将为该布尔语句指定零或非零值(取决于它是否为真).然后,awk程序将以该布尔语句的评估值退出.
  4. shell现在将整个$(...)短语的零或非零值替换.这是通过测试来查看它是否等于1.
  5. 最后,如果该测试语句等于1,&&则会告诉shell 评估echo语句.因此,如果shell变量$CAPACITY为.9或更大,echo则将打印该语句.

这只是为了比较.8(或者无论容量是多少)的很多阴谋.9,为什么开发人员会这样做呢?

可能是因为BASH shell只能做整数运算.由于$CAPACITY小于一,你不能这样做:

if [[ $CAPACITY -le .9 ]]
then
    echo "Capacity is at 90%"
fi
Run Code Online (Sandbox Code Playgroud)

我可能不会使用awk,而是使用了bc:

OVER_CAPACITY=$(bc <<<"$CAPACITY >= .9")
if [[ ! $OVER_CAPACITY -eq $(true) ]]
then
    echo "Capacity is over 90%"
else
    echo "Every thing is okay"
fi
Run Code Online (Sandbox Code Playgroud)

它本来会多一些,但我希望它能让事情变得更容易理解并使文件更容易维护.