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가 말했듯이 스키마를 참조해야 합니다.
그리고 일부는 단지 오락용
답변2
ast-open( 이를 활성화하는 데 사용할 수 있는 grep
ast-open의 일부로 구축된 경우 grep
내장 함수 ) 을 구현하면 다음 과 같이 정의할 수 있습니다 .ksh93
builtin grep
mygrep
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
python
s를 이용해서 빠르게 뭔가를 만들었어요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"
\?
이미 이스케이프가 있는 문자열(예: 있어서는 안되는 것과 \.
있어서는 \*
안 되는 것 ) 을 처리하는 방법에 대해 생각해야 \.*
하지만 지원하려는 구문이 무엇인지 정확히 알지 못하면 더 많은 노력을 기울일 가치가 없습니다.