评估 bash 中传入的变量

评估 bash 中传入的变量

有没有办法将变量作为参数传递给 bash 脚本,并由 bash 脚本对其进行评估?

给定:

# cat /path/to/file/of/host/names
bob
tom
joe
etc...


# dofor
FILE=$1
shift
CMD=$*

while read host; do
    # recursively turns "ssh \$host hostname" from $@ into:
    # ssh bob hostname
    # ssh tom hostname
    # ssh joe hostname
    # etc...
    eval $CMD
done < $FILE

什么时候:

# dofor /path/to/file/of/host/names "ssh \$host hostname"

然后ssh host hostname:我会收到对 /path/to/file/of/host/names 中列出的每个主机名运行的输出。例如:

bob.example.com
tom.example.com
joe.example.com
etc...

答案1

尝试这个:

#!/bin/bash

FILE=$1
shift
CMD=$*
cmds=""

source <({
cat $FILE | while read host; do
    echo $CMD | sed -e "s|\$host|$host|g"
done
})

答案2

您可以使用

#!/bin/bash
FILE=$1
exec 3<$FILE
while read -u 3 host; do
    $2 $host $3
done

那么如果你有:

$ cat /tmp/hostnames
some.host1.com
another.host2.net
some.host3.org    
some.host4.com

然后运行dofor.sh /tmp/hostnames ssh ls,它将按顺序运行:

ssh some.host1.com ls
ssh another.host2.net ls
ssh some.host3.org ls
ssh some.host4.com ls

编辑1:

如果您想更改sshls为一些更长的命令(或其中的一部分),只需使用引号:

dofor.sh /tmp/hostnames "ssh -p 23" "ls -lh /"

编辑2:

使用以下脚本,您将能够$host在命令中的任意位置使用变量:

#!/bin/bash
exec 3<$1
while read -u 3 host; do
    eval $2
done

(我把这个缩短了——没有引入无用的$FILE变量。)这里重要的部分是你需要使用单引号包含 $host 变量的命令周围:

 dofor.sh /tmp/hostnames 'echo "trying $host :"; ssh -p 23 myuser@$host "ls -lh /"'

谨防使用它是危险的eval(参见l0b0 的墙)因为如果文件/tmp/hostnames在某行包含命令,它将被执行。最好不要用它作为root

答案3

这应该可行,但这是一个真的坏主意,除非你完全控制内容$FILE 它只包含非常简单的语句。

while read -r
do
    $REPLY
done < $FILE

对于 SSH 示例,您可以通过循环主机名来完成更简单的操作:

while read -r host
do
    echo -n "${host}:"
    ssh "$host" hostname
done 9< "$FILE"

这应该返回一个my hostname:remote hostname条目列表。

如果您有一个包含实际命令的文件,则必须确保正确处理空格。唯一能够处理的办法任何参数(包括例如echo参数为多行的命令)将使用自定义格式。一种相对简单的方法是用 ␀ 字符分隔每个命令和参数,并在命令的最后一个参数和下一个命令之间放置一个额外的 ␀ 字符。

相关内容