awk에서 bash 함수를 호출하는 방법은 무엇입니까?

awk에서 bash 함수를 호출하는 방법은 무엇입니까?

이것은 약간 까다롭습니다. 이 문제를 해결하는 가장 좋은 방법을 찾으려고 노력하고 있습니다. 몇 가지 방법이 있지만 정말 구식으로 보이고 좀 더 우아한 방법을 원합니다.

#comment lines정확히 4개의 필드가 없는 비어 있지 않은 줄을 무시하고 불평하면서 공백으로 구분된 파일을 구문 분석하고 싶습니다 . 그것은 간단합니다 awk:

awk '/^#/ {next}; NF == 0 {next}; NF != 4 {exit 1}; (dostuff)'

내가 원하는 비결은 바로 이것하다데이터를 사용하여 실제로 변수로 설정한 bash다음 bash$2에 특정 값이 포함되어 있지 않으면 함수를 실행합니다.

다음은 제가 의미하는 바를 설명하기 위한 일부 유사 코드(주로 실제이지만 혼합된 언어)입니다.

# awk
/^#/ {next}
NF == 0 {next}
NF != 4 {exit 1}
$2 == "manual" {next}
# bash
NAME=$1
METHOD=$2
URL=$3
TAG=$4
complicated_bash_function_that_calls_lots_of_external_commands
# then magically parse the next line with awk.

awk파일의 각 줄에 대해 개별적 으로 호출하거나 개별적으로 호출하는 것과 같은 추악한 해결 방법 없이는 이 작업을 수행하는 방법을 모르겠습니다 . sed(원래 나는 "awk에서 bash 함수를 어떻게 호출하거나 bash에서 awk의 각 출력 라인을 호출합니까?"라는 질문을 던졌습니다.)

어쩌면 bash 함수를 자신만의 스크립트로 수정하고 위의 매개변수 1, 2, 3, 4를 허용하도록 만들 수도 있습니다. 그러나 awk에서 호출하는 방법을 잘 모르겠습니다. 따라서 내 질문의 제목입니다.

내가 실제로 무엇을 할 것인가?선호하다해야 할 일은 모든 것을 파일에 넣고 bash 스크립트로 만드는 것입니다. 에서 호출하는 것이 아니라 awk내부에서 호출 해야 합니다.bashbashawkbash 기능awk에서 - 입력 파일의 주석이 아닌 각 줄에 대해 한 번씩.

어떻게 해야 하나요?

답변1

awk출력을 루프로 파이프하여 while read원하는 것을 달성 할 수 있습니다 . 예를 들어:

awk '/^#/ {next}; NF == 0 {next}; NF != 4 {exit 1} ; {print}' | 
    while read -r NAME METHOD URL TAG ; do
        :  # do stuff with $NAME, $METHOD, $URL, $TAG
        echo "$NAME:$METHOD:$URL:$TAG"
    done

if [ "$PIPESTATUS" -eq 1 ] ; then
    : # do something to handle awk's exit code
fi

시험용:

$ cat input.txt 
# comment
NAME METHOD URL TAG
a b c d
1 2 3 4
x y z
a b c d

$ ./testawk.sh input.txt 
NAME:METHOD:URL:TAG
a:b:c:d
1:2:3:4

x y z다섯 번째 입력 줄에서는 올바르게 종료됩니다 .


while루프가 파이프의 대상이기 때문에 하위 쉘에서 실행된다는 점을 지적할 가치가 있습니다 .할 수 없는상위 스크립트의 환경(환경 변수 포함)을 변경합니다.

필요한 경우 파이프를 사용하지 말고 리디렉션 및 프로세스 대체를 사용하십시오.

while read -r NAME METHOD URL TAG ; do
  :  # do stuff with $NAME, $METHOD, $URL, $TAG
  echo "$NAME:$METHOD:$URL:$TAG"
done < <(awk '(/^#/ || NF == 0) {next};
              NF != 4 {
                printf "%s:%s:Wrong number of fields\n", FILENAME, NR > "/dev/stderr";
                exit 1
               };
              {print}' input.txt)

# getting the exit code from the <(...) requires bash 4.4 or newer:
wait $!

if [ "$?" -ne 0 ] ; then
 : # something went wrong in the process substitution, deal with it
fi

또는 coproc내장 명령을 사용하여 백그라운드에서 awk 스크립트를 코프로세스로 실행할 수 있습니다.

# By default, array var $COPROC holds the co-process' stdout and
# stdin file descriptors.   See `help coproc`.
coproc {
  awk '(/^#/ || NF == 0) {next};
       NF != 4 {
         printf "%s:%s:Wrong number of fields\n", FILENAME, NR > "/dev/stderr";
         exit 1
       };
       {print}' input.txt
}
awkpid="$!"
#declare -p COPROC # uncomment to see the FDs

while read -r NAME METHOD URL TAG ; do
  echo "$NAME:$METHOD:$URL:$TAG"
done <&"${COPROC[0]}"

wait "$awkpid"
echo "$?"

답변2

cas의 답변은 훌륭하지만 실제로 awk에서 출력을 다시 구문 분석해야 하고 첫 번째 awk 명령에서 수행하려는 경우 awk에서 환상적인 파이프 명령 구문을 사용할 수 있습니다.

awk '
{
  cmd = "echo name:tag:url:method" # (very simple example)
  while (cmd | getline)
  {
    #process output ($0)
    print
  }
  close(cmd)
}
'

관련 정보