"예기치 않은 개행 문자 또는 문자열 끝"에 대해 불평하는 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빈 문자열로 확장되고 현재 작은따옴표가 존재하지 않음). 이는 이라는 파일에서 실행되는 프로그램의 awk구문 오류(누락) 로 해석됩니다.},,}

참조 문제를 피하고 유지 관리가 더 쉬운 프로세스를 만들 수 있도록 스크립트를 실제 스크립트 파일에 넣고 원격 호스트에서 실행하는 것이 좋습니다.

또한,

  1. read결과를 반복하는 while대신 루프에서 사용하십시오 .forcat
  2. 특히 내부 스크립트의 여러 위치에 필요한 참조가 부족합니다. 예를 들어 grep [0-9]파일 이름 글로빙을 트리거하지 않도록 하기 위해 필요합니다 .
  3. grep eth*이상해 보이네요. 그런 뜻 이었습니까 grep -e 'eth.'? 현재 디렉터리에서 로 시작하는 모든 이름을 선택하기 위한 파일 이름 글로빙 패턴 역할을 하는 것 외에도 eth패턴(정규 표현식으로 해석되는 경우)도 일치하고 et그 뒤에는 0개 이상이 옵니다 h.
  4. 바라보다*sh 쉘에서는 백틱(예: "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}따옴표로 묶이지 않으며 그 주위의 작은 따옴표는 원격 셸에 도달하지 않습니다.

이 문제를 해결하는 한 가지 방법은 다음 문서를 사용하여 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"따옴표로 묶으십시오. 이렇게 하면 로컬 셸에 대한 인용 문제가 해결되지만 원격에 대해서는 glob( 및 ) $1처럼 보이는 항목을 인용해야 합니다 .[0-9foo*

tr인수에는 대괄호가 필요하지 않습니다 a-z(해를 끼치지는 않으며 a 와 마찬가지로 a를 [a로 변경하라고 지시할 뿐입니다 ). 출력에 인터페이스 이름이 포함되어 있다고 생각하지만 이를 대문자로 사용하면 이름이 달라집니다.[]netstat

답변3

경로 변경:

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

도착하다:

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

관련 정보