awk 시스템 호출 Linux - awk에서 쉘을 호출할 때 확장 정규식 사용

awk 시스템 호출 Linux - awk에서 쉘을 호출할 때 확장 정규식 사용

awk에서 시스템 명령을 호출할 수 있다는 것은 매우 유용합니다. 그러나 정규식의 셸 확장을 사용하려고 하면 작동하지 않는다는 것을 알게 될 것입니다.

이는 요즘 Linux에서 예상되는 것처럼 awk가 /bin/bash 대신 /bin/sh를 호출하기 때문입니다.

awk에서 시스템을 호출할 때 확장 정규식이 작동하도록 하려면 어떻게 해야 합니까?

답변1

awk가 완벽하게 작동할 수 있는데 왜 bash에서 그렇게 많은 작업을 수행해야 하는지 이해가 되지 않습니다.

BEGIN {
    filename[0]="/media/Pan/test-data/The_long_file.gz";
    filename[1]="/media/Pan/test-data/The_long_file";

    for (n=0; n<2; n++) {
        print "Contents  of file: " filename[n];

        if (filename[n] ~ /\.gz$/) {
            command = "gunzip --to-stdout " filename[n]
            while (( command | getline file_contents ) > 0 ) {
                print file_contents
            }
            close(command)
        }
        else {
            while (( getline line < filename[n]) > 0 ) {
                print line
            }
        }
    }
}

답변2

awk에서 시스템 명령을 호출할 수 있다는 것은 매우 유용합니다. 그러나 정규식의 셸 확장을 사용하려고 하면 작동하지 않는다는 것을 알게 될 것입니다.

이는 요즘 Linux에서 예상되는 것처럼 awk가 /bin/bash 대신 /bin/sh를 호출하기 때문입니다.

덜 혼란스러운 해결책이 있습니다. 다양한 파일에서 정보를 읽어야 하는 경우(일부는 압축되어 있고 일부는 그렇지 않음) awk에서 다음과 같이 확장 정규식을 사용할 수 있습니다.

BEGIN   {
        filename[0]="/media/Pan/test-data/The_long_file.gz";
        filename[1]="/media/Pan/test-data/The_long_file";
        for ( n=0;n<2;n++)
                {
                print "Contents  of file: " filename[n];
                command="exec /bin/bash -c \"[[ \"" filename[n] "\" =~ .gz ]] \
                &&gunzip --to-stdout " filename[n] "\
                ||cat " filename[n] "\"";
                while (( command | getline file_contents ) > 0 )
                        print file_contents;
                }
        }

이 예에서는 동일한 파일 /media/Pan/test-data/The_long_file의 내용을 두 번 나열합니다. 한 번은 압축 버전으로, 한 번은 일반 텍스트로 나열합니다.

위 내용을 테스트하려면 test.awk에 복사하고 압축된 파일과 압축되지 않은 파일 두 개를 만든 다음 파일 이름[0]과 [1]에 해당 이름을 입력하고 실행합니다.

awk -f test.awk </dev/null

예제 자체는 그다지 유용하지 않지만 이스케이프 문자와 따옴표가 올바른 위치에 있고 /bin/sh를 /bin/bash로 바꾸는 것이 가능하다는 것을 알고 있습니다.

이것이 구문을 올바르게 이해하는 데 걸리는 시간을 일부 사람들이 절약할 수 있기를 바랍니다.

위의 코드는 /bin/sh를 exec로 대체하여 awk가 /bin/sh를 호출하여 발생한 문제를 해결합니다. 쉘에 전달된 코드는 다음과 같습니다.

 exec /bin/bash -c "[[ \"filename\" =~ .gz ]] &&gunzip --to-stdout filename ||cat filename"

Bash가 실행하는 코드는 다음과 같습니다.

 [[ "filename" =~ .gz ]] &&gunzip --to-stdout filename ||cat filename

위의 확장 정규식은 "filename"이 ".gz" 표현식과 일치하는지 확인합니다. 그렇다면 gunzip을 실행합니다. 그렇지 않은 경우 해당 파일만 캡처합니다. "."를 대체하여 정규식을 향상시킬 수 있습니다. "."를 사용하면 "."에만 일치하고 "$"를 사용하면 줄 끝에서만 일치합니다. 명확성을 위해 이렇게 하지 않았습니다.

관련 정보