awk에서 전체 파이프 입력 읽기

awk에서 전체 파이프 입력 읽기

내가 아는 한 awk는 두 가지 방법으로 사용될 수 있습니다. 파일 목록을 매개변수로 전달하거나 파이프라인에서 사용할 수 있습니다. 파일 목록을 매개변수로 사용해 보았으므로 BEGINand END블록은 모든 파일에 대해 한 번만 실행됩니다. 하지만 문제가 있습니다. 파일을 awk에 전달하려면 먼저 파일의 암호를 해독해야 합니다. 그래서 다음과 같이 파이프라인을 설정했습니다.

find . -name "*.gpg" -exec sh -c "gpg -d {} | awk -f process.awk" \;

이제 모든 파일이 실행 BEGIN되고 END차단되는데 process.awk이는 내가 원하는 것이 아닙니다. 블록이 한 번만 실행되도록 awk에 전달된 파일을 해독하는 방법이 있습니까? 업데이트: 파일 이름도 필요하기 때문에 process.awk파일 내용을 별도로 가져오는 것이 더 좋을 것이라고 생각했습니다. 하지만 그러면 찾은 모든 파일에 대해 한 번만 수행해야 한다는 요구 사항을 위반하게 됩니다. 맞습니까 BEGIN?END

답변1

파일 이름에 개행 문자가 포함되어 있지 않다고 가정합니다.

while IFS= read -r fname; do
    gpg -d "$fname"
done < <(find . -name '*.gpg') |
awk -f process.awk

지금 말하는 작업을 수행하고 각 파일 이름을 awk에 전달하려면 가장 간단한 방법은 다음과 같습니다(bash 4.*를 사용 readarray하거나 mapfile채우는 루프를 작성한다고 가정 fnames[]).

readarray -t fnames < <(find . -name '*.gpg')
for fname in "${fnames[@]}"; do
    gpg -d "$fname" |
    awk -v fname="$fname" -v tot="${#fnames[@]}" -v nr="$((++nr))" -f process.awk
done

이렇게 하면 각 파일 이름이 있고 fname코드가 및 섹션에서 실행되는지 테스트할 수 있습니다.nr==1BEGINnr==totEND

BEGIN {
    if (nr==1) {
        do BEGIN stuff
    }
}
{ do common stuff }
END {
    if (nr==tot) {
        do END stuff
    }
}

또는 임시 파일을 위한 공간이 있는 경우 호출을 반복 gpg하고 모든 출력을 동일한 이름의 파일에 대한 임시 디렉터리에 쓴 다음 변경하지 않고도 각 파일에 대해 awk를 호출할 수 있습니다 process.awk.

tmpdir=$(mktemp -d) &&
while IFS= read -r fname; do
    gpg -d "$fname" > "$tmpdir"/"$fname"
done < <(find . -name '*.gpg') &&
awk -f process.awk "$tmpdir"/* &&
rm -rf "$tmpdir"

관련 정보