awk를 사용하여 여러 파일에 헤더를 추가하는 방법

awk를 사용하여 여러 파일에 헤더를 추가하는 방법

여러 파일에 공백이 포함된 헤더 줄을 추가하고 싶습니다.

이것이 내가 지금까지 가지고 있는 것입니다:

#!/bin/bash
# script name is "add_header.sh"
# ARG1 = HEADER STRING
# ARG2,3,... = ARRAY OF FILES TO ADD HEADER TO, RELATIVE DIRECTORY

HEADER=$1 
shift 

for FILE in $@; do
    awk -v HEADER=$HEADER FILE=$FILE 'BEGIN{print HEADER} {print}' FILE > FILE.new
done

불행히도 내 사용 사례에서 실행하면 공백으로 인해 실패합니다.

touch file1 file2 file3
./add_header.sh "some header with spaces" file1 file2 file3

그러면 다음과 같은 오류가 발생합니다.

awk: fatal: cannot open file `with' for reading (No such file or directory)
awk: fatal: cannot open file `with' for reading (No such file or directory)
awk: fatal: cannot open file `with' for reading (No such file or directory)

Bash 변수에서 공백을 이스케이프 처리하는 방법이 있습니까? 각 공백 앞에 \를 사용해 보았지만 이제 오류가 다음과 같이 변경됩니다.

./add_header.sh "some\ header\ with\ spaces" file1 file2 file3
awk: fatal: cannot open file `with\' for reading (No such file or directory)
awk: fatal: cannot open file `with\' for reading (No such file or directory)
awk: fatal: cannot open file `with\' for reading (No such file or directory)

이는 공백이 이스케이프되지 않음을 의미합니다.

답변1

#!/bin/sh

header=$1; shift

for pathname do
    { printf '%s\n' "$header"; cat -- "$pathname"; } >"$pathname.new"
done

awk헤더와 이전 파일 내용을 연결하려고 하므로 여기서는 실제로 필요하지 않습니다 . 간단히 헤더 문자열을 출력한 printf다음 를 사용하여 파일 내용을 출력하면 cat됩니다 . printf출력을 cat새 파일로 리디렉션 합니다 .

당신은 할 수 있습니다진짜를 사용하여 이를 수행하려면 awk위 코드와 같이 파일을 반복하거나 awk명시적인 쉘 루프 없이 각 파일을 처리하도록 할 수 있습니다.

명시적인 쉘 루프가 있는 첫 번째 변형:

#!/bin/sh

header=$1; shift

for pathname do
    header=$header awk 'BEGIN { print ENVIRON["header"] }; 1' "$pathname" >"$pathname.new"
done

awk위의 솔루션은 파일당 한 번 호출 되므로 이 답변의 모든 변형 중에서 가장 느립니다 .

쉘이 없는 루프의 두 번째 변형(GNU처럼 이해해야 함 awk):BEGINFILEawk

#!/bin/sh

header=$1; shift

header=$header awk '
    BEGINFILE { fname = FILENAME ".new"; print ENVIRON["header"] >(fname) }
    { print >(fname) }' "$@"

세 번째 변형(마지막 코드 조각의 이식 가능한 변형):

#!/bin/sh

header=$1; shift

header=$header awk '
    FNR == 1 { fname = FILENAME ".new"; print ENVIRON["header"] >(fname) }
    { print >(fname) }' "$@"

답변2

빈 입력 파일이 없다고 가정하면 올바른 방법은 다음과 같습니다.

#!/usr/bin/env bash
header=$1 
shift 

awk -v header="$header" '
    FNR==1 { close(out); out=FILENAME ".new"; $0=header ORS $0 }
    { print > out }
' "$@"

위 코드는 awk를 사용하는 모든 Unix 시스템의 모든 쉘에서 작동합니다. 빈 입력 파일이 있는 경우 이를 조정해야 합니다.

답변3

나에게 맞는 수정된 버전은 다음과 같습니다.

#!/bin/bash

header=$1
shift

for file in $@; do 
    awk -v HEADER="$header" 'BEGIN{print HEADER} {print}' "$file" > "$file".new
done

awk 표현식 내에서 사용해 보았지만 {print > [FILE].new}작동하지 않습니다. 아마도 stdoutawk에서는 새 파일을 생성할 수 없기 때문일 것입니다.

관련 정보