이스케이프 시퀀스를 평가하기 위해 명령줄에 인수를 전달할 수 있기를 원합니다 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+2
3개의 문자로 구성되고 값이 숫자인 표현식인 것과 같습니다 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;
}