Bash, 검색 문자열과 일치하는 콘텐츠를 찾는 기능

Bash, 검색 문자열과 일치하는 콘텐츠를 찾는 기능

특정 검색 문자열에 대해 bash에 정의된 모든 함수를 검색하고 싶습니다. 아래는 시작이지만 모든 용어를 제거하고 싶습니다.아니요다음 줄 뒤에는 공백이 옵니다(즉, $1함수 본문에서 찾을 수 없는 항목을 제거합니다).

fu() { declare -f | grep -e \(\) -e $1; }

예를 들어 다음 출력은 다음과 같습니다.

...
tt ()
untargz ()
urlfix ()
ver ()
    [ -f /etc/lsb-release ] && RELEASE="$(cat /etc/lsb-release | grep DESCRIPTION | sed 's/^.*=//g' | sed 's/\"//g') ";
vi. ()
vi.su ()
...

로 감소됩니다

...
ver ()
    [ -f /etc/lsb-release ] && RELEASE="$(cat /etc/lsb-release | grep DESCRIPTION | sed 's/^.*=//g' | sed 's/\"//g') ";
...

(가능한 경우) 더 나은 접근 방식은 각 일치 함수를 전체적으로 결정하고 표시할 수 있는 것입니다.

내 생각은 대략 다음과 같다.

  • 본문에서 함수 이름과 검색 문자열을 수집한 다음(함수 이름은 항상 일치 항목 앞 줄에 있는 단일 단어로, 에서 시작하고 그 뒤에 공백이 오고 에서 끝나는 줄이 옵니다) 다음 을 사용합니다 . ^각 함수의 이름을 지정하거나 다시 수행합니다. 하지만 이번에는 해당 이름을 가져와서 그 뒤의 모든 항목을 from ( 여기서 한 줄에 있는 각 항목과 일치 시킵니다 . grep/awk/sed가 지식 것들.()$command -Vdeclare -f{}{}^

fu awk최종 결과가 실행되고 함수 본문에 포함된 각 함수의 정의가 표시됩니다 .awk

답변1

awk파이프의 수신 측에서 다음 명령을 생각해냈습니다.

declare -f | awk -v srch="pattern" 'NF==2 && $2=="()"{if (m) print buf; buf=""; m=0}
                                    buf && index($0,srch){m=1}
                                    {buf=buf ORS $0}
                                    END{if (m) print buf}'

buf아이디어는 출력을 구문 분석할 때 각 함수의 선언과 본문을 버퍼에 저장 declare -f하지만 검색 문자열이 발견될 때만 버퍼를 인쇄하는 것입니다.

  • ()두 번째 필드가 2개의 필드(= 공백으로 구분된 "단어")만 포함된 행을 발견하면 프로그램은 새 함수 정의의 시작을 인식합니다. 이전 함수를 구문 분석할 때 일치하는 항목이 발견되면(플래그 1로 표시됨) m버퍼가 인쇄됩니다. buf버퍼와 플래그가 모두 재설정됩니다.
  • awk검색어는 프로그램에 변수로 전달됩니다 srch. 현재 행에서 발견되면( index함수는 0이 아닌 결과를 반환함) m플래그는 1로 설정되지만, 함수 선언이 시작되는 행에 있지 않은 경우에만( buf비어 있지 않음으로 표시), 그렇지 않으면 일치하는 기능이 있습니다이름중요합니다.
  • 각 줄은 버퍼에 추가되며 buf출력 레코드 구분 기호(기본값은 개행)로 ORS이전 내용과 구분됩니다 .
  • 마지막으로 일치하는 항목이 발견되면 또 다른 검사가 수행되고 발견되면 버퍼가 인쇄됩니다. 이 확인이 없으면 마지막 함수 정의가 고려되지 않습니다.

노트

index()이 프로그램에서 사용하는 함수는 전체 문자열 검색을 수행합니다 awk. 정규식 일치를 기반으로 검색하려면 기준을 다음으로 변경해야 합니다.

index($0,srch)

도착하다

$0~srch

(그러나 항상 그렇듯이 정규식에 특별한 의미가 있는 문자가 포함된 문자열을 검색하는 것이 더 번거롭다는 점에 유의하십시오.)

답변2

에서 동일한 작업을 수행하고 zsh본문이 패턴과 일치하는 함수의 함수 정의를 얻으려면 다음을 수행할 수 있습니다.

typeset -f '<dummy>' ${(k)functions[(R)pattern]}

<dummy>일치하는 기능이 없는 경우를 가리기 위해 사용됩니다 . 또는 더 깔끔한 방법:

() { (($#)) && typeset -f -- "$@"; } ${(k)functions[(R)pattern]}

에서는 bash다음과 같은 작업을 수행할 수 있습니다.

compgen -A function | (
  ret=1
  while IFS= read -r fn; do
    def=$(typeset -f -- "$fn") &&
      [[ ${def#*'()'} = pattern ]] &&
      printf '%s\n' "$def" &&
      ret=0
  done
  exit "$ret"
)

하지만 함수 이름 목록을 한 번에 한 바이트씩 읽고( read입력이 파이프이기 때문에) 각 함수가 프로세스를 포크하기 때문에 이는 상당히 비효율적입니다. 다음과 같은 방법으로 최적화할 수 있습니다.

compgen -A function | (
  readarray -t functions
  for fn in "${functions[@]}"; do
    typeset -f -- "$fn" && printf '\0'
  done
) | (
  ret=1
  readarray -td '' fn_definitions
  for def in "${fn_definitions[@]}"; do
    [[ ${def#*'()'} = pattern ]] &&
      printf '%s\n' "$def" &&
      ret=0
  done
  exit "$ret"
)

readarray대조적으로 read, 어쨌든 모든 입력을 소비하기 때문에 입력을 한 번에 1바이트씩 읽을 필요가 없습니다. 해당 문자는 어쨌든 함수 정의/이름 또는 변수 내용에 저장될 수 없기 때문에 함수 정의를 NUL 문자로 구분합니다. bash그런 다음 이를 사용하여 (bash-4.4+ 필요) 이를 배열로 분해할 수 있습니다.zshreadarray -td ''

()이렇게 하면 출력에서 ​​각 함수 정의가 시작되는 위치를 추측하기 위해 (함수 본문 내에서도 발생할 가능성이 있는) 경험적 방법의 존재에 의존할 필요가 없습니다 typeset -f.

관련 정보