단어 수를 세고 그 수를 변수에 할당하는 더 우아한 방법이 있습니까?

단어 수를 세고 그 수를 변수에 할당하는 더 우아한 방법이 있습니까?

스크립트가 있습니다.

#!/bin/bash

/root/xiotech status > xiostatus.tmp
SyncCount=$(grep -c Sync xiostatus.tmp)
PauseCount=$(grep -c paused xiostatus.tmp)
CopyingCount=$(grep -c Copying xiostatus.tmp)

if [ "$SyncCount" -eq "11" ]
then echo All 11 mirrors are in sync.

else echo $PauseCount mirrors are paused and $CopyingCount mirrors are syncing.
fi

rm -f xiostatus.tmp

awk와 같은 것을 사용하여 이러한 개수를 계산하고 "변경"하는 더 우아한 방법이 있습니까? 이 경우 파일이 작아서 별 문제가 아니지만, 파일이 900MB라면 3번 탐색하는 데 추가 사이클이 많이 걸릴 것입니다.

답변1

awk전체 스크립트를 쉽게 교체할 수 있습니다.

#!/usr/bin/awk -f

/Sync/ {SyncCount++}
/paused/ {PauseCount++}
/Copying/ {CopyingCount++}

END {
    if(SyncCount == 11)
        print "All 11 mirrors are in sync."
    else
        print (+PauseCount) " mirrors are paused and " (+CopyingCount) " mirrors are syncing."
}

변수를 숫자로 처리하도록 (+var)강제하는 것 입니다 (따라서 변수가 설정되지 않은 경우 출력됩니다). 블록을 사용하여 모든 변수를 초기 값 으로 설정할 수도 있습니다 .awk0BEGIN0

BEGIN {
    SyncCount = PauseCount = CopyingCount = 0
}

파일로 저장하고 실행해 보세요 awk -f /path/to/the/script.awk xiostatus.tmp. 임시 파일이 필요하지 않은 경우에도 이 작업을 수행할 수 있습니다 /root/xiotech status | awk -f /path/to/the/script.awk.

스크립트에 실행 비트를 설정하면 이를 독립 실행형 실행 파일( , 또는 ) awk로 호출할 수 있습니다 ./path/to/the/script.awk xiostatus.tmp/root/xiotech status | /path/to/the/script.awk

답변2

계산하고 싶으신 분들은모두awk 버전인 인스턴스는 계산됩니다.많은 종류의 중복 없음같은 줄에 여러 항목이 있으면 어떻게 되나요?

고쳐 쓰다:이제 다른 용도를 포함했습니다 split(.... 많은match( substr(...현재 더 빠른 방법 아래에 나열된 방법보다 빠릅니다. 이 split(...방법은 다른 방법에 비해 4배 이상 빠르다... (87개 파일, 총 407,612줄에 대해 테스트.
자세한 비교를 위해,마이클 모로젝방법, /Sync/범위 선택 사용(이것은철사각 패턴과 개수가 포함되어 있습니다.모두스키마)는 이 새로운 방법보다 두 배 빠릅니다(동일한 데이터에 대해).

이렇게 빨라지는 또 다른 측면(?) 이점은 split(methos)파일의 유효하지 않은 UTF-8 문자에 대해 상당히 관대하다는 것입니다(구분자 패턴이 아닌 한).구분 기호그 자체가 계산되는 실제 문자열 패턴입니다. 내 테스트 파일 중 일부에는 유효하지 않은 UTF-8이 포함되어 있었고 두 방법에서 다른 결과를 얻는 이유를 알아내는 데 오랜 시간이 걸렸습니다.
문제의 파일이 유효한 UTF-8로 다시 인코딩되면 두 방법 모두 동일한 결과를 생성합니다.

여기에 새로운 더 빠른 방법이 있습니다(4배 이상 더 빠름)... 사용split(...

#!/bin/bash
pat='xx|yy|zz'
awk -v vpat="$pat" 'BEGIN { 
  split(vpat, pat, "|"); for(i in pat) pz++ 
} 
{ if (NF) { for( p in pat ) { ct[p]+=(split( $0, A, pat[p] ) -1) }}
}
END { print " count   pattern"
      for (p=1; p<=pz; p++) { printf "%6d   %s\n", +ct[p], pat[p] } 
}' file

이것이 더 느린 방법입니다. 사용match( substr(...

#!/bin/bash
# Count occurrences of multiple non-overlapping string patterns
awk 'BEGIN {
  pattern[1]="xx"
  pattern[2]="yy"
  pattern[3]="zz"
}
{ for( p in pattern ) {
    LHB=0; RSTART=RLENGTH=1
    while( match( substr( $0, LHB+=(RSTART+RLENGTH-1)), pattern[p] )){
      count[p]++ 
    }
  }
} END {
  print "occurs  pattern"
  for (p in pattern) {
    printf "%6d  %s\n", +count[p], pattern[p] 
  } 
}' file

입력 파일입니다

xx xx  xx
xx             yy           xx

출력은 다음과 같습니다.

occurs  pattern
     5  xx
     1  yy
     0  zz

답변3

어때요?

eval `/root/xiotech status | grep -Eo 'Sync|paused|Copying' | sort | uniq -c | 
    awk '{print "count_" $2 "=" $1}'`
if [ "$count_Sync" -eq 11 ]; then
    echo All 11 mirrors are in sync.
else
    echo $count_paused mirrors are paused and $count_Copying mirrors are syncing.
fi

grep -Eo여러 패턴("|"로 구분) 검색을 허용 하고 일치하는 문자열만 반환합니다. sort | uniq -c찾은 단어 수를 표시합니다 . awk 스크립트는 "count_"로 시작하는 변수를 생성하도록 새 쉘 명령의 형식을 지정합니다. 마지막으로 eval생성된 셸 명령은 셸에서 가져와 평가됩니다.

관련 정보