繁体   English   中英

如何在bash变量中使用linux命令

[英]How to use linux commands in bash variables

我正在尝试创建一个bash脚本来执行以下命令的相同操作:

dig -x 8.8.8.8 | grep PTR | cut -d ' ' -f 2 | grep google | cut -f 5

输出为google-public-dns-a.google.com.

现在,我创建了脚本test.sh,如下所示:

#!/bin/bash
IP=$1
output1=$(dig -x $IP)
grepg="grep PTR | cut -d ' ' -f 2 | grep google | cut -f 5"
go=$($output1 | $grepg)
echo $go

并将脚本命名为./test.sh 8.8.8.8。 但是会出错。 如何使用引号有效地将Linux命令存储在bash变量中?
谢谢

这里有两个问题。

第一个是您要尝试将变量$ouptut1的内容作为命令执行,这只是dig输出。 这不是命令。 您可能是说echo $output1

然后,您尝试将变量$grepg的内容作为管道执行。 但是将一行解析为复合命令的组成部分(管道是复合命令)是在参数扩展之前进行的。 因此,如果执行以下操作:

foo="echo hello | grep hi"
$foo

首先将其分解为单个简单命令,然后将该命令扩展,然后将其解析为参数。 因此,这等效于运行:

echo hello "|" grep hi

通常,将要评估的文本字符串存储在变量中不是一个好主意。 在一些非常特殊的情况下,您可能想要这样做,但是在几乎每种情况下(可能还有您的情况下),都有一种更好的方法。 我会警告您,但如果您真的想将字符串作为命令求值,则可以使用eval ,例如:

go=$(echo $output1 | eval $grepg)

您似乎想要的是定义一个shell函数。 如果您想重复使用该管道几次,并通过它运行几个不同的值,则只需定义一个shell函数即可。 该函数是一个命令,等效于所包含的命令:

function grepg() {
    grep PTR | cut -d ' ' -f 2 | grep google | cut -f 5
}

go=$(echo $output1 | grepg)

为了进一步简化代码,可以避免使用所有中间变量。 如果只是要将dig命令的结果通过管道grepggrepg ,则无需在执行此操作之前将其保存在变量中。 而且,如果您只是将结果回显到stdout,则无需再次将其存储在变量中,只需将输出传递到stdout:

#!/bin/bash
IP=$1
function grepg() {
    grep PTR | cut -d ' ' -f 2 | grep google | cut -f 5
}

dig -x $IP | grepg

我在这里假设您想分解该函数,以便可以在脚本中多次使用它。 如果不是,如果只使用一次,则可以进一步简化为:

#!/bin/bash
IP=$1
dig -x $IP | grep PTR | cut -d ' ' -f 2 | grep google | cut -f 5

请注意,如果要将这样的管道存储在变量中,以便可以使用其他代码来决定两个函数之间的关系,并根据某些条件应用一个或另一个,则建议您定义上述函数,并且然后只将单个函数名称存储在变量中。 这将按照您期望的方式工作:

function grepg() {
    grep PTR | cut -d ' ' -f 2 | grep google | cut -f 5
}

function grepf() {
    # do something else, I'm not creative enough to come up with a good example
}

if [ "$2" = "foo" ]
then
    func=grepg
else
    func=grepf
fi

dig -x $IP | $func

为什么不简单地:

dig -x "$1" | grep PTR | cut -d ' ' -f 2 | grep google | cut -f 5

output1存储dig -x $IP的结果,而不存储命令本身,因为您使用的是$( )

grepg将命令存储为字符串,这很好,但是会给您一些意想不到的结果。

在这行上:

go=$($output1 | $grepg) 

它尝试将dig的输出传递到一个名为"grep PTR | cut -d ' ' -f 2 | grep google | cut -f 5"

您可能想要的是:

#!/bin/bash
IP=$1
output1="dig -x $IP"
grepg="grep PTR | cut -d ' ' -f 2 | grep google | cut -f 5"
go=$(eval $output1 | eval $grepg)
echo $go

dig命令作为字符串存储在output1 ,就像grepg存储另一个命令一样。

另外,这里也需要eval 如果不使用eval它将认为整个字符串是程序名称,而不是后跟参数,管道等的程序名称。

这意味着它正在寻找一个名为"grep PTR | cut -d ' ' -f 2 | grep google | cut -f 5"而不是在grep后跟一个参数,一个管道,等等。

您的管道命令链可以缩短为单个awk命令:

dig -x 8.8.8.8 | awk '/PTR[[:space:]]/{print $NF}'
google-public-dns-a.google.com

如果您也想在同一行中搜索google

dig -x 8.8.8.8| awk '/PTR[[:space:]]/ && /google/ {print $NF}'

要将其输出存储在bash变量中,请使用:

go=$(dig -x 8.8.8.8| awk '/PTR[[:space:]]/{print $NF}')

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM