bash脚本在远程服务器上执行的命令打印输出两次

问题描述:

我的输入文件看起来像文件的下面bash脚本在远程服务器上执行的命令打印输出两次

名称:/ etc/hosts中

10.142.75.6 m1 

10.142.75.7 m2 

10.142.75.8 m3 

的下面脚本将查找主机名在/ etc/hosts中,并且应该打印命令“nproc”的输出,但是它会打印输出两次,一次为ip及其相应的主机名。

for hosts in $(cat /etc/hosts) ; 
do 
    ssh $hosts "uname -a" 
done 
+1

Bash用'10.142.75.6 m1 10.142.75.7 m2 10.142.75.8 m3'代替'$(cat/etc/hosts)'。 – Cyrus

+1

...但是你真的不应该在一般情况下使用'for $(cat ...)'。比方说,你有一个/ etc/hosts行,上面写着'#* ALWAYS NOTIFY [email protected] *之前改变这个*' - 你当前的代码将用一系列文件名替换这些'*'s,然后尝试ssh这些文件。另请参阅[为什么不用'for for'读取行](http://mywiki.wooledge.org/DontReadLinesWithFor) –

+0

顺便说一句,通过使用'bash -x yourscript'运行它可能产生的记录你的脚本正在做什么目前的问题清楚。 –

您可以使用cut仅读取文件的第一列:

for hosts in $(cut -d' ' -f1 < /etc/hosts); 
do 
    echo "jps for $hosts" 
    ssh $hosts "uname -a" 
done 
+0

我不确定我是否看到这个被低估的原因 - 我显然不认为这是理想的,但是在任何方面它唯一的错误*是缺少'$ hosts'中的引号扩张。 –

+0

它也不会跳过hosts文件中的注释,但这也相当小。 –

+0

我不认为人们应该鼓励不好的做法,因为它可能适用于这个特定的文件。 – chepner

目前,你解析每一个字的文件作为主机名 - 使您连接到每台主机首先是其知识产权,然后是其名称。


最好使用BashFAQ #1最佳实践,通过一个文件读取:

# read first two columns from FD 3 (see last line!) into variables "ip" and "name" 
while read -r ip name _ <&3; do 

# Skip blank lines, or ones that start with "#"s 
[[ -z $ip || $ip = "#"* ]] && continue 

# Log the hostname if we read one, or the IP otherwise 
echo "jps for ${name:-$ip}" 

# Regardless, connect using the IP; don't allow ssh to consume stdin 
ssh "$ip" "uname -a" </dev/null 

# with input to FD 3 from /etc/hosts 
done 3</etc/hosts 

在这里,我们把第一列到shell变量ip,第二列(如果有的话)转换为name,并将所有后续列转换为变量_