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

时间:2013-09-27 21:40:12

标签: linux 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变量中? 感谢

4 个答案:

答案 0 :(得分:4)

这里有几个问题。

首先,您尝试作为命令执行变量$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命令的结果输入grepg,则在执行此操作之前无需将其保存在变量中。如果你只是将结果回显到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

答案 1 :(得分:3)

为什么不简单:

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

答案 2 :(得分:1)

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后跟一个参数,后跟一个管道,依此类推。

答案 3 :(得分:0)

您的管道命令链可以缩短为单个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}')