비교 성능 테스트수락된 답변

비교 성능 테스트수락된 답변

아래와 같이 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

관련 정보