ssh 命令行中的 awk 抱怨“意外的换行符或字符串结尾”如何解决?

ssh 命令行中的 awk 抱怨“意外的换行符或字符串结尾”如何解决?

运行以下脚本时出现问题,^ 意外的换行符或字符串结尾 我该如何解决此问题?

[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程序存在语法错误(缺少) 。},,}

我建议将脚本放在实际的脚本文件中,并在远程主机上运行它,以避免引用问题并允许您创建更易于维护的过程。

此外,

  1. read在循环中使用while而不是for对 的结果进行循环cat
  2. 特别是内部脚本在几个地方缺乏必要的引用。这是必需的,这样eggrep [0-9]就不会触发文件名通配。
  3. grep eth*看起来很奇怪。你的意思grep -e 'eth.'?除了充当文件名通配模式来拾取当前目录中以 开头的任何名称之外eth,该模式(如果解释为正则表达式)还将匹配et后跟零个或多个h
  4. *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-9foo*) 的内容。

tr不需要参数的方括号a-z(它们不会造成任何伤害,它们只是告诉它将 a 更改[为 a [,与 相同])。尽管我认为它的输出netstat包含接口名称,并且将它们大写会使名称不同。

答案3

更改线路:

mount|awk '{print $1,$3,$5}'|sort;

到:

mount|awk '\''{print $1,$3,$5}'\''|sort;

相关内容