아래와 같이 abd라는 텍스트 파일이 있습니다.
48878 128.206.6.136
34782 128.206.6.137
12817 23.234.22.106
텍스트에서 IP 주소를 추출하여 저장하고 싶습니다.바꾸다그리고 다른 목적으로.
나는 그것을 시도했다.
for line in `cat abd`
do
ip=`grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' $line`
echo $ip
done
아래와 같이 오류가 발생합니다.
grep: 34782: No such file or directory
grep: 128.206.6.137: No such file or directory
grep: 12817: No such file or directory
grep: 23.234.22.106: No such file or directory
여기서 무엇이 잘못되었는지 모르겠습니다. 어떤 도움이라도 대단히 감사하겠습니다.
답변1
처음에는 거의 맞췄습니다. 대답은 특정 사례에 적용되지만 오류가 발생하는 이유는 변수가 아닌 파일을 검색하는 데 awk
사용하려고 하기 때문입니다 .grep
또한 정규식을 사용할 때는 항상 grep -E
안전하게 사용합니다. 또한 백틱은 더 이상 사용되지 않으며 $()
.
grep
지원되는 쉘에서 변수를 사용하는 올바른 방법여기에 있는 문자열다음 중 3개에서 입력 리디렉션을 사용하고 있으므로 <
명령 grep
( $ip
변수)은 실제로 다음과 같아야 합니다.
ip="$(grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' <<< "$line")"
while
파일을 검색하는 경우 한 줄씩 이동하는 것이 보장되므로 항상 루프를 사용 하지만 for
이상한 간격이 있는 경우 일반적으로 루프가 발생합니다. 또한 cat
입력 리디렉션으로 대체할 수 있는 쓸모없는 사용도 구현했습니다 . 이 시도:
while read line; do
ip="$(grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' <<< "$line")"
echo "$ip"
done < "abd"
또한 사용 중인 OS나 버전이 무엇인지는 모르지만 grep
과거에 이 명령을 사용할 때마다 중괄호 앞의 이스케이프 문자는 일반적으로 필요하지 않습니다. 따옴표 없이 백틱 없이 사용하거나 사용하여 발생할 수 있습니다 grep -E
. 모르겠습니다. 그것을 사용하거나 사용하지 않고 시도해 보고 무슨 일이 일어나는지 확인할 수 있습니다.
for
루프를 사용할지 아니면 while
루프를 사용할지 여부는 특정 상황에 어떤 루프가 적합한지, 그리고 실행 시간이 가장 중요한지에 따라 달라집니다. OP는 각 IP 주소에 대해 별도의 변수를 할당하려고 하는 것이 아니라 루프 자체에서 사용할 수 있도록 줄의 각 IP 주소에 대해 변수를 할당하려는 것 같습니다. 이 경우 $ip
반복당 하나의 변수만 필요합니다. 나는 이 문제에 대해 확고한 입장을 견지합니다.
답변2
IP 주소가 항상 파일의 두 번째 필드인 경우 awk
또는 cut
를 사용하여 추출할 수 있습니다.
awk '{print $2}' abd
또는
cut -d' ' -f2 abd
IP 주소를 반복해야 하는 경우 일반 for
또는 루프를 사용할 수 있습니다. while
예를 들어:
for ip in $(cut -d' ' -f2 abd) ; do ... ; done
또는
awk '{print $2}' abd | while read ip ; do ... ; done
또는 모든 IP 주소를 배열로 읽을 수 있습니다.
$ IPAddresses=($(awk '{print $2}' abd))
$ echo "${IPAddresses[@]}"
128.206.6.136 128.206.6.137 23.234.22.106
답변3
grep
파일이나 표준 입력에서 패턴을 검색합니다. grep
명령줄에서 일치시킬 데이터 문자열을 전달할 수 없습니다 . 이 시도:
grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' abd
변수의 각 IP 주소를 가져와야 하는 경우:
grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' abd |
while read IP
do
echo "$IP"
done
비교 성능 테스트수락된 답변
대답은 grep
입력 파일의 각 줄에서 별도의 호출을 수행하는 것을 제안합니다. 1000~5000줄 사이의 파일에서 어떤 일이 일어나는지 살펴보겠습니다. 이 파일은 질문의 원본 예제 파일을 복사하여 생성되었습니다 abd.1000
. abd.5000
원래 코드는 ${1:?}
하드코딩된 "abd" 대신 파일 이름을 명령줄 인수( )로 사용하도록 변경되었습니다.
$ wc -l abd.1000 abd.5000
1000 abd.1000
5000 abd.5000
6000 total
1000줄 파일에서 이 답변의 예제 코드를 테스트하세요.
$ cat ip-example.sh
#!/bin/sh
grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' "${1:?}" |
while read IP
do
echo "$IP"
done
$ time sh ip-example.sh abd.1000 > /dev/null
real 0m0.021s
user 0m0.007s
sys 0m0.017s
$
위에 표시된 이 답변의 예는 1/4초 이내에 1000줄 파일을 처리합니다. 이제 허용된 답변의 예가 어떻게 수행되는지 살펴보겠습니다.
$ cat accepted.sh
#!/bin/bash
while read line; do
ip="$(grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' <<< "$line")"
echo "$ip"
done < "${1:?}"
$ time bash accepted.sh abd.1000 > /dev/null
real 0m3.565s
user 0m0.739s
sys 0m2.936s
$
음. 허용된 답변의 예는 약 3 1/2초 안에 실행됩니다.169배 느림이 답변 예에서는 1/40초 이상입니다.
좀 더 노력해서 5000개의 행으로 테스트해 보겠습니다.
$ time sh ip-example.sh abd.5000 > /dev/null
real 0m0.052s
user 0m0.051s
sys 0m0.029s
~에 대한두 배그냥 처리해5배 더 많은 데이터.
$ time bash accepted.sh abd.5000 > /dev/null
real 0m17.561s
user 0m3.817s
sys 0m14.333s
허용되는 답변의 예제 코드에는 거의5배 더 길어짐1000행의 데이터보다 5배 더 많은 데이터를 처리했습니다.
결론적으로
허용되는 답변의 예는 다음과 같습니다.337배 더 길어짐이 답변의 코드 대신 5000줄 파일을 처리하세요 ip-example.sh
(이 페이지의 다른 답변도 비슷한 작업을 수행해야 함 ip-example.h
).
답변4
첫 번째 질문 보기배쉬 FAQ:
while read -r _ ip; do printf "%s\n" "${ip[@]}"; done < abd
128.206.6.136
128.206.6.137
23.234.22.106