有没有办法将变量作为参数传递给 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:
如果您想更改ssh
或ls
为一些更长的命令(或其中的一部分),只需使用引号:
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
参数为多行的命令)将使用自定义格式。一种相对简单的方法是用 ␀ 字符分隔每个命令和参数,并在命令的最后一个参数和下一个命令之间放置一个额外的 ␀ 字符。