awk 내에서 사용자 정의 bash 함수 사용

awk 내에서 사용자 정의 bash 함수 사용

어떻게 든 AWK 내에서 bash 기능을 사용할 수 있습니까?

예제 파일(문자열, int, int, int)

Mike 247808 247809 247810

값을 10진수에서 16진수로 변환하려고 합니다.

.bashrc쉘 스크립트 내부 또는 내부에 정의된 함수입니다 .

$ awk '{print $1 ; d2h($2)}' file

awk: calling undefined function d2h
 input record number 1, file file
 source line number 1

답변1

기능을 사용해 보세요 system():

awk '{printf("%s ",$1); system("d2h " $2)}' file

귀하의 경우에는 이 명령의 출력을 system호출 한 다음 출력에 추가합니다.d2h 247808printf

Mike 3C800

편집하다:

대신 system에 액세스 sh하는 bash방법을 찾을 수 없습니다 .bashrc. 하지만 현재 bash 스크립트의 기능을 계속 사용할 수 있습니다.

#!/bin/bash
d2h() {
    # do some cool conversion here
    echo "$1" # or just output the first parameter
}
export -f d2h
awk '{printf("%s ",$1); system("bash -c '\''d2h "$2"'\''")}' file

참고: 다음과 -f같은 데 사용됩니다.함수 내보내기변수보다는요.

편집 2:

이유는 모르겠지만 Ubuntu 16.04에서는 작동하지 않습니다. Ubuntu 14.04에서 작동했기 때문에 이것은 이상합니다.

답변2

awk에서 bash를 호출하고 해당 출력을 사용할 수 있습니다. 너무 자주 발생하면 성능 측면에서 분명히 위험합니다. 매뉴얼 페이지를 인용하면 다음과 같습니다.

command | getline [var]

출력을 $0 또는 var로 파이프하는 명령을 실행합니다.

명령은 함수 정의를 포함하고 함수를 실행하는 bash 스크립트입니다.

답변3

10진수에서 16진수로 변환하는 것은 awk그 자체로 매우 잘 수행될 수 있는 작업입니다. 그리고 당신은awk이를 수행하는 기능:

function d2h(d) {
  return sprintf("%x", d)
}

이제 일반적인 경우의 질문에 대답하려면 함수를 awk실행 하려면 해당 함수의 정의를 해석하고 인수로 전달된 값을 사용하여 해당 함수를 호출하는 셸을 실행 bash해야 합니다 .awkbashbashawk

사소한 것이 아닙니다.

bash는 환경을 통한 함수 내보내기를 지원하므로 이후 의 호출에서 사용할 수 있습니다 . 따라서 호출된 bash에 함수 정의를 전달하는 한 가지 방법입니다 .bashawk

export -f d2h

awk명령( bash여기) 을 실행 하는 유일한 방법은 해당 system("cmd"), 또는 print... | "cmd"또는 을 사용하는 것입니다 "cmd" | getline. 모든 경우에 는 awk셸을 실행하여 를 해석 하지만 가 아닌 가 cmd됩니다 . 따라서 함수를 호출하기 위해 명령줄을 해석하는 호출에 대한 명령줄을 구성해야 하므로 인용에 주의해야 합니다.shbashshbashbash

export -f d2h
<file awk -v q="'" '
  function shquote(s) {
    gsub(q, q "\\" q q, s)
    return q s q
  }
  {print $1; system("exec bash -c '\''d2h \"$1\"'\'' bash " shquote($2))}'

함수의 출력을 다시 로 가져오려면 awk파이프를 통해 다시 전송해야 합니다. 이를 위해서는 (의 stdout을 그대로 유지하는) cmd | getline대신 을 사용합니다 .system(cmd)cmd

cmd | getline line백화점한 줄(엄밀히 말하자면하나의 기록, 레코드는 기본적으로 라인임), 여러 라인으로 구성된 경우 전체 출력을 얻으려면 다음과 같은 루프가 필요합니다.

awk '...
  cmd = "exec bash -c '\''d2h \"$1\"'\'' bash " shquote($2)
  output = ""
  while ((cmd | getline line) > 0) {
    output = output line RS
  }
  sub(RS "$", "", output) # remove the last newline
  ...'

sh이는 함수를 호출할 때마다 하나씩 실행한다는 의미 bash이므로 상당히 비효율적입니다. 이는 bash다음을 사용하여 읽고 분할하는 것보다 훨씬 더 비효율적입니다 while read loop.

(unset -v IFS; while read -r a b rest; do
  printf '%s\n' "$a"
  d2h "$b"
 done < file)

또한 Shellshock 이후로 bash이제 BASH_FUNC_d2h%%. 최신 버전을 포함한 일부 sh구현mkshdash 제거하다환경의 해당 환경 변수:

$ env 'foo%%=bar' dash -c 'printenv foo%%'
$ env 'foo%%=bar' mksh -c 'printenv foo%%'
$ env 'foo%%=bar' zsh  -c 'printenv foo%%'
bar
$ env 'foo%%=bar' bash -c 'printenv foo%%'
bar

따라서 허술한 함수 내보내기 기능에 의존하는 대신 다른 방법으로 함수 정의를 전달할 수 있습니다. 일반적인 이름의 환경 변수를 통해 이루어질 수 있습니다.

BASH_FUNCTIONS=$(typeset -f d2h) awk '
   ...
   cmd = "exec bash -c '\''eval \"$BASH_FUNCTIONS\";" \
         "d2h \"$1\"'\'' bash " shquote($2)
   ...'

답변4

awk 내에서 사용자 정의 bash 함수 사용

부인 성명:나는 이것이 OP가 하려는 것이 아니라는 것을 알고 있지만 Google은 나와 같은 다른 사람들을 이 답변으로 이끌 것입니다.

상황

bash(자신이나 [대부분의] 동료를 싫어하지 않기 때문에) 함수로 구성된 스크립트가 있고 해당 함수 중 적어도 하나는 내부에서 다른 함수를 호출해야 합니다 awk.

해결책

스크립트

#!/bin/env bash

# The main function - it's a sound pattern even in BASH
main(){
    # In the awk command I do some tricky things with single quotes. Count carefully...
    # The first $0 is outside the single quotes so it is the name of the current bash script.
    # The second $0 is inside the single quotes so it is awk's current line of input.
    awk '{printf("%s. ", ++c); system("'$0' --do"); print $0}'<<-PRETEND_THIS_IS_AN_INPUT_STREAM
        and
        and
        well
    PRETEND_THIS_IS_AN_INPUT_STREAM
}

# functionized to keep things DRY
doit(){
    echo -n "doin' it "
}


# check for a command switch and call different functionality if it is found
if [[ $# -eq 1 && $1 == "--do" ]];
then
        doit
else
        main
fi

산출

$ ./example.sh
1. doin' it and
2. doin' it and
3. doin' it well

관련 정보