gawk에 인수로 전달된 이스케이프 시퀀스는 해석되지 않습니다.

gawk에 인수로 전달된 이스케이프 시퀀스는 해석되지 않습니다.

이스케이프 시퀀스를 평가하기 위해 명령줄에 인수를 전달할 수 있기를 원합니다 gawk.

질문:

$ gawk 'BEGIN { print ARGV[1]; }' '\t'
\t

대신 실제 탭 문자를 얻고 싶습니다.

~에서gawk 문서:

문자열 상수 및 정규식 상수의 경우 이전 목록의 이스케이프 시퀀스가 ​​항상 먼저 처리됩니다. awk가 프로그램을 읽으면 아주 초기에 이런 일이 발생합니다.

명령줄 인수에서 문자 이스케이프를 해석하는 방법은 무엇입니까?

최종 목표는 myscript.awk --sep '\t'구분 기호가 형식 문자열이므로 리터럴 탭을 전달하는 것은 옵션이 아닙니다. 나는 또한 bash에서 이 작업을 수행하는 쉬운 방법에 익숙하지만 [g]awk에서 수행하는 방법에 관심이 있습니다.

답변1

명령줄 인수의 이스케이프되지 않은 버전을 인쇄하는 방법은 무엇입니까?

print ARGV[1]

문제는 이스케이프되지 않은 명령줄 매개변수를 원하지 않는다는 것입니다. 당신은 그것을 설명하고 싶어합니다. (2문자 문자열 백슬래시, 소문자 T)를 전달하고 \t이를 백슬래시로 변환하려고 합니다. 이 작업은 수동으로 수행해야 합니다. 탭으로 변환하는 것은 \t쉽습니다. gsub(/\\t/, "\t")그러나 8진수 이스케이프를 지원하고 인식할 수 없는 문자 앞의 백슬래시를 제거하려는 경우 이는 awk에서 번거로울 수 있습니다.

split ARGV[1], a, "\\";
s = a[1]; delete a[1];
for (x in a) {
    if (skip_next) {
        skip_next = 0;
    } else if (x == "") {
        s = s "\\";
        skip_next = 1;
    } else if (x ~ /^[0-7][0-7][0-7]/) {
        s = s sprintf("%c", 64*substr(x,1,1) + 8*substr(x,2,1) + substr(x,3,1));
        sub(/^.../, x);
    } else if (x ~ /^[0-7][0-7]/) {
        s = s sprintf("%c", 0 + 8*substr(x,1,1) + substr(x,2,1));
        sub(/^../, x);
    } else if (x ~ /^[0-7]/) {
        s = s sprintf("%c", 0 + substr(x,1,1));
        sub(/^./, x);
    } else {
        sub(/^a/, "\a", x) ||
        sub(/^b/, "\b", x) ||
        sub(/^n/, "\n", x) ||
        sub(/^r/, "\r", x) ||
        sub(/^t/, "\t", x) ||
        sub(/^v/, "\v", x);
    }
    s = s x;
}

printf(경고: 테스트되지 않은 코드!) 이 복잡한 코드를 사용하는 대신 서브셸에서 호출할 수 있습니다. 문자열이 여러 줄인 경우에도 이 작업은 쉽지 않습니다.

s = ARGV[1]
gsub(/'/, "'\\''", s)
cmd = "printf %b '" s "'."
s = ""
while ((cmd | getline line) > 0) s = s line "\n"
sub(/..$/, "", s)

awk 스크립트를 작성할 때 "\t"이는 탭 문자를 포함하는 문자열이라는 점에 유의하세요. awk 구문은 다음과 같습니다. 백슬래시는 문자열 리터럴에서 특별한 의미를 갖습니다. 참고:문자열 리터럴, 하나도 아니야. 문자열에 백슬래시가 포함되어 있으면 이는 또 다른 문자일 뿐입니다. 소스 코드 조각은 "\t"4개의 문자로 구성되며 값이 탭 문자를 포함하는 단일 문자 문자열인 표현식입니다. 소스 코드 조각이 2+23개의 문자로 구성되고 값이 숫자인 표현식인 것과 같습니다 4.

awk 스크립트에서는 구분 기호 매개변수를 리터럴 문자열로 사용하는 것이 더 좋습니다. 이렇게 하면 사용이 더 쉬워집니다. 인터페이스에서는 호출자가 인수에서 백슬래시를 이스케이프해야 합니다. 구분 기호를 탭 문자로 지정하려면 실제 탭 문자를 전달하세요.

답변2

첫째, 실제로 탭을 에 전달하지 않습니다 awk. 쉘이 인수를 평가한다는 것을 기억하십시오.앞으로이는 따옴표로 전달되고 awk따옴표 '\t'\리터럴 내에서 평가됩니다 \t.

$ set -x
$ gawk 'BEGIN { print ARGV[1]; }' '\t'
+ gawk 'BEGIN { print ARGV[1]; }' '\t'
\t

위에서 볼 수 있듯이 탭을 전달하지 않으므로 gawk탭이 인쇄될 것이라고 거의 기대할 수 없습니다. 이것을 탭을 통과하는 아래 버전과 비교해 보세요.

$ gawk 'BEGIN { print ARGV[1]; }' "$(printf '\t')"
++ printf '\t'
+ gawk 'BEGIN { print ARGV[1]; }' ' '  ## note the tab
                         ## This line contains a printed tab

또는 탭을 변수로 전달할 수 있습니다.

gawk -v t='\t' 'BEGIN {print t}'

여기서 '\t'확장은 쉘이 아닌 awk에 의해 수행되므로 탭이 올바르게 해석됩니다.

답변3

해결책은 를 사용하는 것입니다 getline.

파일에서:

BEGIN { 
    sep = ARGV[1]
    gsub(/'/, "'\\''", sep);
    gsub(/%/, "%%", sep);
    "printf -- '" sep "'" | getline sep; 
    printf sep;
}

관련 정보