특정 검색 문자열에 대해 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 -V
declare -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+ 필요) 이를 배열로 분해할 수 있습니다.zsh
readarray -td ''
()
이렇게 하면 출력에서 각 함수 정의가 시작되는 위치를 추측하기 위해 (함수 본문 내에서도 발생할 가능성이 있는) 경험적 방법의 존재에 의존할 필요가 없습니다 typeset -f
.