!["예기치 않은 개행 문자 또는 문자열 끝"에 대해 불평하는 ssh 명령줄의 awk를 수정하는 방법은 무엇입니까?](https://linux55.com/image/126600/%22%EC%98%88%EA%B8%B0%EC%B9%98%20%EC%95%8A%EC%9D%80%20%EA%B0%9C%ED%96%89%20%EB%AC%B8%EC%9E%90%20%EB%98%90%EB%8A%94%20%EB%AC%B8%EC%9E%90%EC%97%B4%20%EB%81%9D%22%EC%97%90%20%EB%8C%80%ED%95%B4%20%EB%B6%88%ED%8F%89%ED%95%98%EB%8A%94%20ssh%20%EB%AA%85%EB%A0%B9%EC%A4%84%EC%9D%98%20awk%EB%A5%BC%20%EC%88%98%EC%A0%95%ED%95%98%EB%8A%94%20%EB%B0%A9%EB%B2%95%EC%9D%80%20%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C%3F.png)
다음 스크립트를 실행할 때 문제가 있습니다. ^ 예기치 않은 줄바꿈 또는 문자열 끝이 발생했습니다. 어떻게 해결할 수 있나요?
[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
구문 오류(누락) 로 해석됩니다.}
,,}
참조 문제를 피하고 유지 관리가 더 쉬운 프로세스를 만들 수 있도록 스크립트를 실제 스크립트 파일에 넣고 원격 호스트에서 실행하는 것이 좋습니다.
또한,
read
결과를 반복하는while
대신 루프에서 사용하십시오 .for
cat
- 특히 내부 스크립트의 여러 위치에 필요한 참조가 부족합니다. 예를 들어
grep [0-9]
파일 이름 글로빙을 트리거하지 않도록 하기 위해 필요합니다 . grep eth*
이상해 보이네요. 그런 뜻 이었습니까grep -e 'eth.'
? 현재 디렉터리에서 로 시작하는 모든 이름을 선택하기 위한 파일 이름 글로빙 패턴 역할을 하는 것 외에도eth
패턴(정규 표현식으로 해석되는 경우)도 일치하고et
그 뒤에는 0개 이상이 옵니다h
.- 바라보다*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-9
foo*
tr
인수에는 대괄호가 필요하지 않습니다 a-z
(해를 끼치지는 않으며 a 와 마찬가지로 a를 [
a로 변경하라고 지시할 뿐입니다 ). 출력에 인터페이스 이름이 포함되어 있다고 생각하지만 이를 대문자로 사용하면 이름이 달라집니다.[
]
netstat
답변3
경로 변경:
mount|awk '{print $1,$3,$5}'|sort;
도착하다:
mount|awk '\''{print $1,$3,$5}'\''|sort;