运行以下脚本时出现问题,^ 意外的换行符或字符串结尾 我该如何解决此问题?
[root@emrbldbgdapd2 ~]# ./collectdata.sh
collect the data of 10.209.61.124
awk: cmd. line:1: {print
awk: cmd. line:1: ^ unexpected newline or end of string
collect the data of 10.209.61.125
awk: cmd. line:1: {print
awk: cmd. line:1: ^ unexpected newline or end of string
[root@emrbldbgdapd2 ~]#
==========
[root@emrbldbgdapd2 ~]# more collectdata.sh
for i in `cat test`
do echo "collect the data of $i"
ssh -o LogLevel=error -o ConnectTimeout=5 $i 'hostname;
echo "############################";
free -g;
echo "######################################";
echo "######################################";
netstat -nr | grep [0-9] | tr [a-z] [A-Z];
echo "######################################";
echo "######################################";
mount|awk '{print $1,$3,$5}'|sort;
echo "######################################";
echo "######################################";
ip a s | grep -i eth*;
echo "######################################"'>output/$i-`date "+%d%b%Y"`
done
[root@emrbldbgdapd2 ~]#
答案1
您试图在单引号字符串中使用单引号。第一个内部单引号与管道位于同一行mount | awk | sort
,将终止该行上启动的单引号ssh
。
实际错误来自awk
.它得到一个看起来像这样的命令行{print ,,}
(由于$1
, $3
,$5
被调用 shell 扩展为空字符串,并且此时单引号不存在)。这被解释为在名为 的文件上运行的awk
程序存在语法错误(缺少) 。}
,,}
我建议将脚本放在实际的脚本文件中,并在远程主机上运行它,以避免引用问题并允许您创建更易于维护的过程。
此外,
read
在循环中使用while
而不是for
对 的结果进行循环cat
。- 特别是内部脚本在几个地方缺乏必要的引用。这是必需的,这样eg
grep [0-9]
就不会触发文件名通配。 grep eth*
看起来很奇怪。你的意思grep -e 'eth.'
?除了充当文件名通配模式来拾取当前目录中以 开头的任何名称之外eth
,该模式(如果解释为正则表达式)还将匹配et
后跟零个或多个h
。- 看*sh shell 中的反引号(即“cmd”)是否已被弃用?关于您对反引号的使用。
修改后的脚本:
#!/bin/sh
now=$( date +%d%b%Y )
if [ -d output ]; then
echo 'Output directory missing' >&2
exit 1
fi
while read host; do
printf 'Collecting data from "%s"...\n' "$host"
ssh -n -o LogLevel=error -o ConnectTimeout=5 "$host" \
sh <<'END_SCRIPT' >output/"$host-$now"
echo '## HOSTNAME:'
hostname
echo '## FREE:'
free -g
echo '## NETSTAT:'
netstat -nr | grep '[0-9]' | tr 'a-z' 'A-Z'
echo '## MOUNT:'
mount | awk '{ print $1, $3, $5 }' | sort
echo '## IP:'
ip a s | grep -i 'eth.*'
END_SCRIPT
done <hosts.txt
答案2
正如其他答案中提到的,问题在于在远程运行的命令中使用单引号。正如 SE 上的语法着色所示,{print $1,$3,$5}
没有被引用,并且它周围的单引号不会到达远程 shell。
解决这个问题的一种方法是通过 stdin 使用此处文档将脚本发送到远程:
ssh somehost /bin/sh > outputfile <<"EOF"
hostname
free -g
netstat -nr | grep "[0-9]" | tr "[a-z]" "[A-Z]"
mount | awk '{print $1,$3,$5}' | sort
# and so on
EOF
将 here-doc 分隔符放在"EOF"
引号中,以便$1
本地 shell 不会扩展变量。这应该可以解决本地 shell 的引用问题,但您仍然需要为远程引用内容,例如任何看起来像 glob ([0-9
和foo*
) 的内容。
tr
不需要参数的方括号a-z
(它们不会造成任何伤害,它们只是告诉它将 a 更改[
为 a [
,与 相同]
)。尽管我认为它的输出netstat
包含接口名称,并且将它们大写会使名称不同。
答案3
更改线路:
mount|awk '{print $1,$3,$5}'|sort;
到:
mount|awk '\''{print $1,$3,$5}'\''|sort;