Bash에서 여러 줄 awk 스크립트를 실행하는 방법

Bash에서 여러 줄 awk 스크립트를 실행하는 방법

이 스크립트를 시작하려면 쉘 bash를 사용하여 Github 워크플로를 실행하고 가독성을 위해 yaml을 자릅니다. 나는 주석을 달 수 있도록 여러 줄로 작동하도록 많은 노력을 기울였습니다.

  set -x
  set -e
  AWK_SOURCE=$( cat <<- AWK
  '
    {
      if ( $1 !~ /delete/ # ensure we are not trying to process deleted files
      && $4 !~ /theme.puml|config.puml/ # do not try to process our theme or custom config
      && $4 ~ /.puml/ ) # only process puml files
      { printf "%s ", $4 } # only print the file name and strip newlines for spaces
    }
    END { print "" } # ensure we do print a newline at the end
  '
  AWK
  )
  GIT_OUTPUT=`git diff-tree -r --no-commit-id --summary ${GITHUB_SHA}`
  AWK_OUPUT=`echo $GIT_OUTPUT | awk -F' ' $AWK_SOURCE`
  echo "::set-output name=files::$GIT_OUTPUT"
  set +e
  set +x

이것은 나의 현재 오류입니다

이것을 한 줄로 실행하면 잘 작동합니다.

git diff-tree -r --no-commit-id --summary HEAD | awk -F' ' '{ if ( $1 !~ /delete/ && $4 !~ /theme.puml|config.puml/ && $4 ~ /.puml/ ) { printf "%s ", $4 } } END { print "" }'

이것은 현재 나타나는 출력/오류입니다. 다른 출력/오류가 나타납니다.

shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
+ set -e
++ cat
+ AWK_SOURCE=''\''
  {
    if (  !~ /delete/ # ensure we are not trying to process deleted files
    &&  !~ /theme.puml|config.puml/ # do not try to process our theme or custom config
    &&  ~ /.puml/ ) # only process puml files
    { printf "%s ",  } # only print the file name and strip newlines for spaces
  }
  END { print "" } # ensure we do print a newline at the end
'\'''
++ git diff-tree -r --no-commit-id --summary 6c72c8a8dabf19ae2439ee506b9a4a636027193e
+ GIT_OUTPUT=' create mode 100644 .config/plantuml/config.puml
 create mode 100644 .config/plantuml/theme.puml
 delete mode 100644 config.puml
 create mode 100644 docs/README.md
 create mode 100644 docs/domain-model/README.md
 create mode 100644 docs/domain-model/user.md
 create mode 100644 docs/domain-model/user.puml
 delete mode 100644 theme.puml
 delete mode 100644 user.puml
 delete mode 100644 user.svg'
++ echo create mode 100644 .config/plantuml/config.puml create mode 100644 .config/plantuml/theme.puml delete mode 100644 config.puml create mode 100644 docs/README.md create mode 100644 docs/domain-model/README.md create mode 100644 docs/domain-model/user.md create mode 100644 docs/domain-model/user.puml delete mode 100644 theme.puml delete mode 100644 user.puml delete mode 100644 user.svg
++ awk '-F ' \' '{' if '(' '!~' /delete/ '#' ensure we are not trying to process deleted files '&&' '!~' '/theme.puml|config.puml/' '#' do not try to process our theme or custom config '&&' '~' /.puml/ ')' '#' only process puml files '{' printf '"%s' '",' '}' '#' only print the file name and strip newlines for spaces '}' END '{' print '""' '}' '#' ensure we do print a newline at the end \'
awk: cmd. line:1: '
awk: cmd. line:1: ^ invalid char ''' in expression
+ AWK_OUPUT=

주석이 달린 여러 줄 awk를 유지하는 방법은 무엇입니까?

답변1

다음과 같이 변수가 아닌 함수에 코드를 넣으세요(테스트되지 않았으나 여전히 개선의 여지가 있음).

set -x
set -e
do_awk() {
    awk '
        ($1 !~ /delete/) &&                 # ensure we are not trying to process deleted files
        ($4 !~ /theme.puml|config.puml/) && # do not try to process our theme or custom config
        ($4 ~ /.puml/) {                    # only process puml files
            printf "%s ", $4                # only print the file name and strip newlines for spaces
        }
        END { print "" }                    # ensure we do print a newline at the end
    ' "${@:--}"
}
GIT_OUTPUT=$(git diff-tree -r --no-commit-id --summary "$GITHUB_SHA")
AWK_OUPUT=$(printf '%s\n' "$GIT_OUTPUT" | do_awk)
echo "::set-output name=files::$GIT_OUTPUT"
set +e
set +x

답변2

주요 문제는 코드가 인용되지 않아 쉘이 awk코드의 내용을 대체할 수 있다는 것입니다. $4셸에서 코드를 보호하려면 여기에 설명서를 인용하세요. 시작 구분 기호를 따옴표( <<'AWK'또는 에서와 같이 <<"AWK")로 묶거나 이스케이프 하여 여기에서 문서를 인용할 수 있습니다 <<\AWK.

내가 작성한 방식으로 스크립트를 다시 작성하면 다음과 같습니다.

git diff-tree -r --no-commit-id --summary "$GITHUB_SHA" |
awk '
    $1 !~ /^delete/ && $4 !~ /(theme|config)\.puml$/ && $4 ~ /\.puml$/ {
        name[++n] = $4
    }
    END {
        $0 = ""
        for (i in name) $i = name[i]
        printf "::set-output name=files::%s\n", $0
    }'

중간 데이터를 변수에 저장하지 않는다는 점에 유의하세요. 이는 비효율적입니다(모르실 수도 있습니다).얼마나변수에 저장된 데이터가 필요하며 인용 오류가 발생하기 쉽습니다. 대신 공백에 값을 뱉어내고 파일 이름 글로빙을 호출합니다. 이 점에서 $GIT_OUTPUT따옴표를 사용하거나 사용하지 않는 것은 문제가 되며 , 쉘 구성에 따라 백슬래시가 포함된 경우 데이터가 수정될 수 있기 때문에 특히 문제가 됩니다.$AWKecho $GIT_OUTPUTecho

인용에 관해서: 참조언제 큰따옴표가 필요합니까?

구문 분석하려는 문자열이 포함된 pattern { action }배열을 작성하기 위해 스크립트에서 표준 구문을 사용하고 있습니다 . nameEND블록에서는 출력 레코드를 생성 $0하고 출력에 사용한 접두사를 사용하여 출력합니다 echo.

이렇게 하면 댓글을 작성할 수 있는 공간이 더 많아집니다.

git diff-tree -r --no-commit-id --summary "$GITHUB_SHA" |
awk '
    $1 ~ /^delete/ {
        # skip these
        next
    }
    $4 ~ /(theme|config)\.puml$/ {
        # and these...
        next
    }
    $4 ~ /\.puml$/ {
        # pick out filename (we assume no whitespace in filenames)
        name[++n] = $4
    }
    END {
        $0 = ""
        for (i in name) $i = name[i]
        printf "::set-output name=files::%s\n", $0
    }'

여기에 있는 문서에 소스 코드를 넣으 려면 awk다음과 같이 하십시오.

awk_script=$(mktemp) || exit 1
trap 'rm -f "$awk_script"' EXIT

cat <<'AWK_CODE' >"$awk_script"
$1 !~ /^delete/ && $4 !~ /(theme|config)\.puml$/ && $4 ~ /\.puml$/ {
    name[++n] = $4
}
END {
    $0 = ""
    for (i in name) $i = name[i]
    printf "::set-output name=files::%s\n", $0
}
AWK_CODE

git diff-tree -r --no-commit-id --summary "$GITHUB_SHA" |
awk -f "$awk_script"

즉, 나중에 호출 되고 스크립트 끝에서 삭제되는 awk임시 파일에 스크립트를 저장합니다 (여기서 사용됨 ). 그러나 이렇게 짧은 프로그램의 경우 작은 따옴표로 묶인 문자열에 스크립트를 사용하는 것과 비교하여 이 작업을 수행하면 추가 이점이 없습니다(첫 번째 참조). 혼란스럽고 많은 내용이 포함되어 있습니다.awk -ftrapawk추가 명령실행해야 하는 두 개의 중앙 명령을 제외하고 유지 관리용으로만 사용됩니다.

답변3

가독성과 유지 관리 측면에서 가장 쉬운 방법은 awk스크립트를 임시 파일로 보낸 다음 다음을 통해 가져오는 것입니다 awk.

awksrc=$(mktemp) || exit 1
cat << 'EOF' > "${awksrc}"
{
  if ( $1 !~ /delete/ # ensure we are not trying to process deleted files
       && $4 !~ /theme.puml|config.puml/ # do not try to process our theme or custom config
       && $4 ~ /.puml/ 
  ) # only process puml files
      { printf "%s ", $4 } # only print the file name and strip newlines for spaces
}
END { print "" } # ensure we do print a newline at the end
EOF
echo "$GIT_OUTPUT" | awk -f "${awksrc}" 
rm -f "${awksrc}"

답변4

저는 GitHub Workflow를 사용해본 적이 없지만문서에 따르면사용자 정의 셸을 사용할 수 있습니다. 당신이 말하는 경우:

steps:
  - name: process puml files
    run: <your awk script here>
    shell: awk -f {0}

또는 그것의 일부 순열을 사용하면 쉘 헛소리 없이 원시 awk 스크립트를 실행할 수 있어야 합니다.

관련 정보