쉘 스크립트에서 시간이 많이 걸리므로 GREP 대신 SED 또는 AWK를 사용하는 방법

쉘 스크립트에서 시간이 많이 걸리므로 GREP 대신 SED 또는 AWK를 사용하는 방법

테스트 케이스 이름과 PASSED/FAILED 상태를 추출하기 위해 다음 코드를 작성했습니다. 테스트 케이스 로그는 다음과 같습니다.: 중간에 줄이 많이 있습니다.

테스트 케이스 이름(예: A_HL_INT_GPRS_CGDSCONT_0000 및 해당 "통과" 또는 "실패" 상태)을 추출하고 싶습니다.

또한 또 다른 질문이 있습니다. grep을 사용하여 쉘 스크립트를 실행했는데 시간이 더 오래 걸렸습니다.

다음 문제를 해결하려면 AWK 또는 SED 명령을 사용해야 합니다.

한 가지 더 필요한 것은 다음과 같이 실패한 모든 테스트 사례 이름을 인쇄해야 한다는 것입니다.

failed testcases list:

A_HL_INT_GPRS_CGDCONT_0002 Failed
A_HL_INT_GPRS_CGDCONT_0003 Failed
A_HL_INT_GPRS_CGDCONT_0004 Failed
Begin of A_HL_INT_GPRS_CGDSCONT_0000 
Passed
End of A_HL_INT_GPRS_CGDSCONT_0000 
Begin of A_HL_INT_GPRS_CGDCONT_0002
FAILED
End of A_HL_INT_GPRS_CGDCONT_0002 
#! /bin/bash
echo "Enter the logfilename : "
read logfilename
echo "Entered name : $logfilename"
echo "outside the while loop"
let success=0
let failure=0
let total=0
DONE=false
until $DONE; do
read line || DONE=true
    echo "$line" | grep "Begin of "
    if (echo "$line" | grep -i "PASSED") then
        ((success++))
    fi
    if (echo "$line" | grep -i "FAILED") then
        ((failure++))
    fi
    if (echo "$line" | grep "End of ") then
        ((total++))
    fi  
done < "$logfilename"   
echo "Total testcases : $total"
echo "Total testcase with Success : $success"
echo "Total testcase with Failure : $failure"

안녕 보도:

귀하의 코드와 일치하는 다음 줄을 추가했습니다.

#! /bin/bash
echo -n "Enter the logfilename : "
read logfilename
echo "Entered name : $logfilename"
echo "outside the while loop"

awk 'BEGIN { IGNORECASE=1; }
/^begin of / { print; count=1; passed=failed=0;}
/^end of / { count=0; totalcount++; if(failed)failcount++;else if(passed)passcount++;}
/passed/ && count { passed=1; }
/failed/ && count { failed=1; }
END {
  print "Total testcases : " totalcount;
  print "Total testcase with Success : " passcount;
  print "Total testcase with Failure : " failcount; }' "logfilename"

안녕하세요 우루텔님,

다음 코드를 수정할 수 있습니까? "Begin of TESTCASENAME" 줄을 제거하고 실패한 테스트 사례를 배열에 저장한 다음 실패한 테스트 사례 목록을 인쇄하려고 합니다. 또한 저는 이 상황을 처리하려고 했습니다. 로그 파일이 존재하지 않으면 어떻게 될까요?

#! /bin/bash
declare -a arr
# if no command line argument is given
# set logfilename to : logfilename not specified
if [ -z $0 ]
then
  logfilename="*** Log filename not specified.***"
elif [ -n $1 ]
then
# otherwise make first arg as logfilename
  logfilename=$1
fi

echo "outside the while loop"
let success=0
let failure=0
let total=0
let fail=0
while read line; do
        case "$line" in
                *Begin\ of\ *)  echo $line;;
                *PASSED*)       ((success++));;
                *FAILED*)       ((failure++))
                    arr[$fail] = $line
                    echo "Shubhra added this line : ${arr[$fail]}"
                    ((fail++));;
                *End\ of\ *)    ((total++));;
        esac
done < "$logfilename"

echo "Total testcases : $total"
echo "Total testcase with Success : $success"
echo "Total testcase with Failure : $failure"
echo "failed testcase list:"
echo ${arr[@]}

답변1

여기서 해결책은 셸에 내장된 명령을 사용하는 것입니다. 이렇게 하면 상대적으로 비용이 많이 드는 한 줄에 여러 개의 분기/실행을 수행할 필요가 없기 때문입니다.

나는 이렇게 할 것이다:

#! /bin/bash
echo -n "Enter the logfilename : "
read logfilename
echo "Entered name : $logfilename"
echo "outside the while loop"
let success=0
let failure=0
let total=0
failedtests=()

while read line; do
        case "$line" in
                *Begin\ of\ *)  echo $line
                                failedtests+=( ${line/Begin of /} )
                                ;;
                *PASSED*)       ((success++));;
                *FAILED*)       ((failure++));;
                *End\ of\ *)    ((total++));;
        esac
done < "$logfilename"

echo "Total testcases : $total"
echo "Total testcase with Success : $success"
echo "Total testcase with Failure : $failure"
echo "Failed tests:" ${failedtests[@]}

case전역 패턴을 일치시키는 데 사용할 수 있습니다 . 예제 데이터(grep에 "pass" 대신 "pass"가 있음)를 기반으로 *각 패턴의 선행 부분을 생략할 수 있지만 이를 사용하면 grep 사용법과 정확히 일치합니다.

DONE또한 최종 빈 문자열(파일 끝에서 생성됨)을 쓸데없이 반복하고 있으므로 변수를 제거했습니다 .

편집: 실패한 테스트의 수집 및 표시가 추가되었습니다. 이것들은 bash 배열에 수집됩니다 failedtests. 결과적으로 문자열의 내용이 삭제됩니다 ${line/Begin of /}. line마지막으로 배열의 전체 내용이 로 표시됩니다 ${failedtests[@]}.

답변2

AWK가 IGNORECASE대소문자를 구분하지 않는 비교를 강제하는 변수를 지원하는 경우 다음 스크립트를 사용할 수 있습니다. (예를 들어 GNU AWK는 Linux에서 이를 지원합니다.)

AWK가 이를 지원하지 않는 경우 다음을 IGNORECASE수행할 수 있습니다.

  • 일치하는 모든 패턴을 대소문자를 구분하지 않는 패턴으로 수정합니다(예: /[Pp][Aa][Ss][Ss][Ee][Dd]/대신 등 /passed/). 또는
  • tolower일치시키려는 값이 있는 함수를 사용하십시오(예: tolower($0) ~ /passed/대신 /passed/).
awk 'BEGIN { IGNORECASE=1; }
/^begin of / { print; count=1; passed=failed=0;}
/^end of / { count=0; totalcount++; if(failed)failcount++;else if(passed)passcount++;}
/passed/ && count { passed=1; }
/failed/ && count { failed=1; }
END {
  print "Total testcases : " totalcount;
  print "Total testcase with Success : " passcount;
  print "Total testcase with Failure : " failcount; }' logfile

이 입력을 사용하십시오(파일에서 logfile).

Begin of A_HL_INT_GPRS_CGDSCONT_0000
Passed
foo
End of A_HL_INT_GPRS_CGDSCONT_0000
Begin of A_HL_INT_GPRS_CGDCONT_0002
bar
passed
FAILED
End of A_HL_INT_GPRS_CGDCONT_0002
Begin of foo
failed
End of bar
foo
Passed
FAILED
bar

나는이 결과를 얻습니다

Begin of A_HL_INT_GPRS_CGDSCONT_0000
Begin of A_HL_INT_GPRS_CGDCONT_0002
Begin of foo
Total testcases : 3
Total testcase with Success : 1
Total testcase with Failure : 2

참고:
스크립트의 편집된 버전은 행 사이 passed또는 failed한 번만 계산되며 우선 순위를 갖습니다. 스크립트는 합계의 식별자가 일치하는지 확인하지 않습니다.begin of ...end of ...failedpassed
begin of ...end of ...

관련 정보