포트 번호를 매개변수로 사용하는 스크립트를 작성하려고 합니다. 아무것도 할당되지 않은 다음 포트를 반환하고 파일을 이용하여 확인합니다 /etc/services
. 포트가 사용 중이면(즉, 문서에 나열됨) 포트를 추가하고 다시 시도합니다. 이 스크립트가 "found"에서 무엇이든 반환하도록 할 수 없는 것 같습니다. 항상 0과 같기 때문에 while 루프에 들어가지 않습니다. 내가 뭘 잘못했나요?
#!/bin/bash
port=$1
found=$(cat /etc/services | grep -o '[[:space:]]$port/' | wc -l)
while [ $found -ge 1 ]; do
$port=$($port+1)
#done
echo "found: $found"
echo "port: $port"
(이전 댓글은 무시하세요 done
. 문제가 되지 않습니다.)
답변1
개요
이 스크립트에는 몇 가지 사소한 버그가 있으며 몇 가지 스타일을 변경해야 합니다. 원본 내용을 한 줄씩 살펴보겠습니다.
#!/bin/bash
port=$1
일반적인 #!
경로와 간단한 임무로 우리는 좋은 출발을 했습니다.
found=$(cat /etc/services | grep -o '[[:space:]]$port/' | wc -l)
이 줄에는 처음에는 눈치채지 못할 작은 문제가 있습니다. $port
그렇기 때문에강력한 참조, '…$port'
, 해당 값으로 확장되지 않습니다. 당신은 사용하고 싶을 것입니다약한 따옴표반대로, "…$port"
. 게다가 cat
여기서는 실제로 필요하지 않습니다. grep
파일 이름을 인수로 허용하지만 그렇지 않은 경우 언제든지 사용할 수 있습니다.리디렉션( grep 'pattern' < /etc/services
). 또한 grep -c
일치하는 행의 개수가 기록되므로 wc -l
이 역시 중복됩니다.
while [ $found -ge 1 ]; do
$port=$($port+1)
done
루프가 보인다거의아름다운. $found
null일 수 있는 경우를 대비하여 테스트에서 엔터티를 참조해야 합니다 . 또한, port=
not 을 사용하여 할당합니다 $port=
(하지만 위에서 올바른 형식을 사용했기 때문에 단지 오타인 것 같습니다). 마지막은 $($port+1)
(예를 들어 if port
is 22
) "명령의 출력 22+1
"을 의미합니다. 분명히 당신은 22+1
매우 유사한 "산술 표현의 결과"를 원합니다 $(($port+1))
.
echo "found: $found"
echo "port: $port"
이 줄은 그대로 두십시오.
논리를 고려하다
이제 위의 모든 사항을 변경하면 프로그램이구문론적으로맞습니다. 그래도 원하는 대로 되지는 않습니다. "올바른" 출력을 나열하지 않았으므로 다음을 원한다고 가정합니다.
found: <the number of occurrences of $1 in /etc/services>
port: <the next free port>
이러한 가정이 잘못된 경우 댓글로 알려주시면 그에 따라 수정하겠습니다.
포트가 제공되면 스크립트는 절대 반환하지 않습니다.하다/etc/services
업데이트하지 않았기 때문에 나타납니다 found
. 따라서 found=…
해당 줄을 루프에 복사하는 것이 현명하다고 생각할 수도 있지만 그렇지 않습니다! 이렇게 하면 스크립트는 항상 를 반환합니다 found: 0
. 내 생각에 가장 좋은 방법은기능:
found () {
grep -co "[[:space:]]$1/" /etc/services
}
그러나 이제 함수의 종료 값을 조건으로 직접 사용할 수 있습니다. 출력과 함께 표시되지 않도록 출력을 무음으로 설정해야 합니다. 그러면 -co
더 이상 플래그가 필요하지 않지만 다음을 수행합니다 -q
.
while found "$port"; do
그런 다음 입력 포트의 발생 횟수를 반환하려면 다음과 같습니다.
echo "found: $(found "$1")"
또는 를 사용할 수 있습니다 printf
.
그것들을 하나로 합치다
나는 이것이 당신이 작성하려는 스크립트라고 생각합니다.
#!/bin/sh
found () {
grep -q "[[:space:]]$1/" /etc/services
}
port=$1
while found "$port"; do
port=$(($port+1))
done
printf 'found: %d\nport %d\n' "$(found "$1")" "$port"
보너스
awk
이 글을 썼을 때 나의 초기 반응은 주어진 패턴과 일치하는 행 수를 계산하는 것도 grep
. 그런 다음 전체 프로그램을 사용할 수 있다는 생각이 들었습니다 awk
. 보너스로 여기에 구현이 있습니다(여기서는 /etc/services
포트 번호별로 정렬되어 있다고 가정하고 있습니다).
#!/usr/bin/awk -f
BEGIN {
FS = "[ \t/][ \t/]*"
ARGC = 2
PORT = ARGV[1]
OPORT = PORT
ARGV[1] = "/etc/services"
}
($2 == OPORT) {
FOUND = FOUND + 1
}
(NEXT == 0 && NR > 1 && $2 > PORT) {
NEXT = ($2 > PORT + 1) ? PORT + 1 : NEXT
PORT = $2
}
END {
printf "found: %d\nport: %d\n", FOUND, (FOUND == 0) ? OPORT : NEXT
}
답변2
수학 부분을 빼면, 원하는 작업을 수행하지만 논리를 구현하기 위해 "while" 루프 조건 대신 "if" 문을 사용하는 빠르고 더러운 POC가 있습니다.
#!/bin/bash
port=$1
echo $port | while read a; do
found=$(cat /etc/services | grep -Eo '[0-9]{1,5}/' | sed 's/^/ /' | grep ' '$a'/')
if [[ $found ]];
then echo port $a is being used
else echo port $a is not being used
fi
done
편집: 문제는 $found 변수에서 발생합니다. grep의 작은따옴표로 인해 $port가 문자 그대로 해석되므로 "80/" 대신 "$port/" 문자열을 grep합니다. 해결 방법: 작은따옴표를 큰따옴표로 바꾸세요.
찾기=$(cat /etc/services | grep -o "[[:space:]]$port/" | wc -l)