grep에는 Bash-Globbing과 유사한 검색 패턴이 있습니다.

grep에는 Bash-Globbing과 유사한 검색 패턴이 있습니다.

grep유사한 명령과 일치시키기 위해 매우 간단한 패턴을 사용하고 싶습니다 . 배경은 VM 이름 목록에 대한 grep입니다. 예를 들어 VM 이름만 나열하는 명령은 이름이 ".local"로 끝나는 VM을 찾고 있습니다.

올바른 것은:

# virsh list --name | grep '\.local$'

나는 다음과 같은 것을 사용하고 싶다

# virsh list --name | mygrep *.local

문자 클래스나 범위 표현식은 필요하지 않지만 셸 와일드카드의 기본 패턴을 적용해야 합니다.

  • *0개 이상의 문자
  • ?하나의 역할에만 해당
  • 패턴의 시작과 끝을 암시하는 문자열의 시작이나 끝을 나타내는 추가 마커가 없습니다.
  • 점은 특별한 의미가 없습니다..

(단순화를 위해 bash의 파일 이름 와일드카드를 먼저 무시하십시오)

답변1

카니발로서기능

mygrep() {
    local pattern=$1 line
    while IFS= read -r line; do
        if [[ $line == $pattern ]]; then
            printf '%s\n' "$line"
        fi
    done
}

==운영자들이 [[...]]있는 곳패턴 매칭운영자.
인용하다:https://www.gnu.org/software/bash/manual/bash.html#index-_005b_005b

그러나 @Panki가 말했듯이 스키마를 참조해야 합니다.


그리고 일부는 단지 오락용

  • function mygrep
      while read --line line
        string match -- $argv[1] $line
      end
    end
    
  • #!/usr/bin/env tclsh
    proc glob_grep {argv} {
        lassign $argv pattern
        while {[gets stdin line] != -1} {
            if {[string match $pattern $line]} {
                puts $line
            }
        }
    }
    glob_grep $argv
    

답변2

ast-open( 이를 활성화하는 데 사용할 수 있는 grepast-open의 일부로 구축된 경우 grep내장 함수 ) 을 구현하면 다음 과 같이 정의할 수 있습니다 .ksh93builtin grepmygrep

mygrep() {
  grep -xK "$@"
}

여기서 -K정규식 스타일을 기본 기본 정규식에서 ksh glob 패턴( bash -O extglob즉, 지원되는 패턴의 상위 집합)으로 전환하고 -x정확한 일치를 켭니다(패턴은 줄의 일부가 아니라 전체 줄과 일치해야 함).

어쨌든 다음과 같이 호출해야 합니다.

virsh list --name | mygrep '*.local'

쉘이 이를 glob으로 해석하는 것을 방지하기 위해 *.local문자 그대로 mygrep함수 에 전달됩니다.

사용하는 경우 zsh다음을 수행할 수 있습니다.

alias mygrep='noglob grep -xK'

인수로 확장되지 않은 글로브의 경우 다음을 mygrep수행할 수 있습니다.

virsh list --name | mygrep *.local

그러나 이는 다음을 수행할 수 없음을 의미합니다.

mygrep *.local ./*.txt

현재 디렉토리의 파일 *.local에서 glob 패턴과 일치하는 행을 찾습니다 ..txt

zsh에서는 배열 요소를 glob 패턴과 일치하지 않는 요소 ${array:#pattern}또는 glob 패턴과 일치하는 요소 로 필터링할 수 있습니다 ${(M)array:#pattern}. 다음을 사용하여 명령 출력의 비어 있지 않은 줄을 배열에 넣을 수 있습니다 ${(f)"$(cmd)"}.

pattern=*.local
print -rC1 -- ${(M)${(f)"$(virsh list --name)"}:#$~pattern}

또는 함수로:

cmdglobline() print -rC1 -- ${(M)${(f)"$("$@[2,-1]")"}:#$~1}
cmdglobline '*.local' virsh list --name

extendedglob옵션을 활성화하면 고급 전역 패턴 연산자(대소문자 구분 없는 일치, 간격 있는 반복, 대략적인 일치, 부정 등)를 얻을 수 있습니다.

답변3

pythons를 이용해서 빠르게 뭔가를 만들었어요fnmatch.filter.

#!/usr/bin/env python3
import fnmatch
import sys

def main():
    try:
        pattern = sys.argv[1]
    except IndexError:
        print('mygrep: No pattern supplied', file=sys.stderr)
        sys.exit(1)

    results = fnmatch.filter([_.rstrip('\n') for _ in sys.stdin.readlines()], pattern)
    for line in results:
        print(line)

if __name__ == '__main__':
    main()

어딘가에 놓고 PATH실행 가능하게 만드십시오. 가장자리가 약간 거칠긴 하지만 트릭을 수행해야 합니다.

주석에서 언급했듯이 파일 이름의 셸 완성을 방지하려면 패턴을 인용해야 합니다.

virsh list --name | mygrep '*.local'

답변4

"globbing과 같은" 구문을 원한다고 하셨기 때문에 어떤 구문을 지원하려는지는 확실하지 않지만 BRE 메타 문자를 비활성화하려면 mygrep()원하지 않는 모든 BRE 메타 문자를 이스케이프 하도록 작성 *하고 로 변경하거나 로 .*변경 하고 grep에게 다음과 같이 지시할 수 있습니다. 와일드카드 구문과 유사한 정의를 얻으려면 전체 줄을 일치시키십시오.?.

$ mygrep() {
    local re
    re=$(sed 's/[.$]/[&]/g; s/?/./g; s/\*/.*/g; s/\^/\\^/g' <<<"$1")
    shift
    printf 'Using grep -x -- "%s"\n' "$re" >&2
    grep -x -- "$re" "$@"
}

$ mygrep '*.local' file
Using grep -x -- ".*[.]local"

\?이미 이스케이프가 있는 문자열(예: 있어서는 안되는 것과 \.있어서는 \*안 되는 것 ) 을 처리하는 방법에 대해 생각해야 \.*하지만 지원하려는 구문이 무엇인지 정확히 알지 못하면 더 많은 노력을 기울일 가치가 없습니다.

관련 정보