POSIX awk 마법사, 당신의 도움이 필요합니다! 언뜻 보면 이 질문이 사소해 보일 수도 있지만, 내 의도를 좀 더 자세히 설명하겠습니다.
나는 독립 실행형 POSIX awk 프로그램을 개발 중이며 95% 완료했지만 올바른 방법을 찾을 수 없습니다. 이에 대해서는 나중에 보여 드리겠습니다.
POSIX sh의 솔루션
먼저, 구현하려는 POSIX sh 솔루션은 다음과 같습니다.
#!/bin/sh
key=$(date +%Y-%m-%d) # results in 2022-08-04
while read -r line; do
awk -v key=$key '$0 ~ key {
for (i = 0; i < 10; i++)
getline current
print current
}' "$line"
done < /tmp/awk.data
위의 코드 조각에서 볼 수 있듯이
awk.data
파일에서 한 번에 한 줄씩 읽고, 반복할 때마다 awk를 호출하고, key
패턴과 일치하는 줄을 검색하고, 일치하면 루프를 실행하고 for
, 9줄을 건너뛰고, 다음을 인쇄합니다. 최종 결과 1.
파일 내용은 다음과 같습니다 awk.data
.
$ cat /tmp/awk.data
/tmp/sample-001.html
/tmp/sample-002.html
/tmp/sample-003.html
# <...>
/var/log/sample-787.html
/var/log/sample-788.html
POSIX awk의 문제를 해결하려고 합니다.
이것은 POSIX awk 프로그램에서 구현하려는 것의 작은 부분이며 지금까지 시도한 내용은 다음과 같습니다. 그러나 성공하지 못했습니다.
#!/usr/bin/awk -f
BEGIN {
date = getdate()
data = "/tmp/awk.data"
# <...>
read(data)
}
function getdate() {
cmd = "date +%Y-%m-%d"
cmd | getline date
close(cmd)
return date
}
function read(data) {
cmd = "cat" " " data
while (cmd | getline line)
parse(line)
close(cmd)
}
function parse(file) {
cmd = "cat" " " file
while (cmd | getline line) {
if (line ~ date) {
for (i = 0; i < 10; i++)
getline current
print current
}
}
close(cmd)
}
이 read
함수는 출력의 각 줄 cat
(예:
/tmp/sample-001.html
etc.) 을 읽고 이를 각 파일을 구문 분석하고 원하는 출력을 생성하는 다른 함수 /tmp/sample-002.html
에 전달합니다 .parse
while
이것은 처리된 각 줄에 루프를 사용한 다음 현재 줄이 변수에 의해 정의된 패턴과 일치하는지 확인하는 첫 번째 시도입니다 date
. 그렇다면 for
루프를 시작하고 9줄을 건너뛰고 마지막 줄을 인쇄합니다. 그것은 매우 가능하다매우
비효율적이지만 프로그램이 실행되지만 영원히 반복되고 아무것도 인쇄되지 않습니다. 완전히 갇혔어요!
다시 말하면,내 awk 프로그램은 어떤 매개변수도 허용하지 않습니다., 따라서 이 경우 awk 내부에서 외부 파일을 읽는 것이 중요합니다.
미리 도움을 주셔서 대단히 감사합니다!
답변1
다음을 수행할 수 있습니다.
#! /usr/bin/awk -f
BEGIN {
ARGC = 1
while ((getline file < "awk.data") > 0)
ARGV[ARGC++] = file
"date +%Y-%m-%d" | getline date
}
FNR == 1 {
line_to_print = 0
}
line_to_print {
if (FNR == line_to_print) {print; nextfile}
next
}
index($0, date) {line_to_print = FNR + 10}
nextfile
아직 POSIX는 아니지만 다음 버전에 포함될 예정입니다. 위 코드는 awk
지원되지 않는 구현에서도 여전히 작동합니다 nextfile
(이 경우 여전히 유효한 코드이지만 아무 작업도 수행하지 않습니다).
awk
POSIX는 Shebang 메커니즘을 지정하지 않으며 유틸리티 경로도 지정하지 않습니다 . shebangs는 호출 될 때 a 가 옵션으로 처리될 수 있기 #! /path/to/awk -f
때문에 신뢰할 수 없습니다 (예를 들어 이와 같은 인수는 GNU 구현에 의해 다시 시작됩니다 ).that-script -x
/path/to/awk -f /path/to/that-script -x
-x
awk
'-eBEGIN{system("reboot")}'
awk
in은 명령줄을 호출하기 위해 호출 "date..." | getline date
하므로 방정식에서 명령줄이 제거 되지 않습니다 . 도움 없이는 명령을 실행할 수 없습니다 . GNU는 현재 날짜의 형식을 지정할 수 있지만 이는 표준이 아닙니다. POSIXly를 사용하여 현재 날짜를 신기원 시간으로 가져올 수 있지만 (그러나 OpenBSD는 이 점에서 POSIX가 아닙니다) 사용자 시간대에 맞게 YYYy-MM-DD 형식으로 변환하는 것은 매우 어렵습니다. 그것을 피한다면 아마도 여기보다 더 나은 언어가 있을 것입니다.awk
sh
sh
awk
sh
awk
srand()
perl
awk
sh
awk.data
행이 다음 foo=bar.html
형식 인 경우 awk
처리할 파일 경로가 아닌 변수 할당으로 처리됩니다. 이 경우 다음을 사용하여 BEGIN 문에서 이러한 경로를 정리할 수 있습니다.
function sanitise(path) {
if (path != "" && path !~ /^\//)
return "./" path
else
return path
}
( ARGV[ARGC++] = sanitise(file)
대신 사용하십시오 ARGV[ARGC++] = file
).
반면 getline file
에 read -r line
선행 및 후행 공백과 탭 문자는 입력 줄에서 제거되지 않습니다. 제거하려면 수동으로 수행해야 합니다.
getline file
sub(/^[ \t]*/, "", file)
sub(/[ \t]*$/, "", file)
예를 들어.
루프와의 또 다른 차이점 while read
은 마지막 줄이 구분되지 않은 경우 여전히 처리되지만 awk
루프에 의해 삭제된다는 것입니다 while read
sh
.