텍스트 파일에 다음 텍스트가 있습니다
$ cat test
20180618:
20180619:
20180620:
20180621:
20180622:
20180623:
20180624:
grep을 사용하여 다음과 같이 숫자의 범위를 찾으려고 합니다.
$ grep 201806{19..21} test
grep: 20180619: No such file or directory
grep: 20180620: No such file or directory
grep: 20180621: No such file or directory
ZSH와 bash 모두에서 위의 오류가 발생합니다. grep이 문자열을 파일로 검색하는 것처럼 보입니다.
나는 다른 방법을 시도했습니다.
$ grep 201806* test
zsh: no matches found: 201806*
ZSH에서만 이 오류가 발생합니다. ZSH에서 이것을 사용하는 올바른 방법은 무엇이며 *
, 숫자 범위에 대해 grep에게 grep을 지시하려면 어떻게 해야 합니까?
답변1
응 grep
그냥 치료해첫 번째기본적으로 매개변수는 정규식으로 사용됩니다.
이것은 의미한다
grep {1..9} file
다음으로 확장
grep 1 2 3 4 5 6 7 8 9 file
grep
with는 1
다른 피연산자와 일치하는 표현식으로 호출되며 이러한 다른 피연산자는 파일 이름이 될 것으로 예상됩니다.
다른 명령:
grep 201806* test
이는 201806*
파일 이름 와일드카드 패턴으로 일치를 시도합니다. 201806
현재 디렉토리에 이름이 다음으로 시작하는 파일이 없으므로 zsh
쉘은 패턴을 확장할 수 없으며 오류 메시지를 표시합니다 no matches found
.
Bourne과 같은 다른 쉘에서는 패턴이 파일 이름과 일치하지 않으면 확장되지 않은 상태로 유지되고 로 사용됩니다 grep
. 표현식이 201806*
정규 표현식으로 처리되면 일치 항목 20180
뒤에 0개 이상의 6
문자가 옵니다(예: ) 2018066666
.
대신, 범위와 일치하는 정규식을 구성할 수 있습니다.
grep -E '201806(19|20|21)' test
또는
grep -E '201806(19|2[01])' test
표현식의 (교대)를 이해해야 합니다 -E
(이 교대로 하면 확장 정규 표현식이 됩니다) grep
.|
중괄호 확장을 통해 정규식을 구성할 수도 있습니다.
set -- {19..21}
re=$( IFS='|'; printf '201806(%s)' "$*" )
grep -E "$re" test
그러면 먼저 위치 매개변수 및 가 범위 내에서 원하는 숫자 $1
로 설정됩니다. 그러면 변수는 로 구분된 숫자로 대체될 위치로 설정됩니다 .$2
$3
re
201806(%s)
printf
%s
|
이 호출은 정규식 grep
으로 사용됩니다 .201806(19|20|21)
답변2
grep 201806{19..21} test
셸을 통해 다음으로 확장되었습니다.
grep 20180619 20180620 20180621 test
이는 3개의 파일을 grep
찾는 것으로 이해될 수 있습니다.20180619
20180620
20180621
test
다음과 같이 변경하면:
grep -e201806{19..21} test
그런 다음 다음으로 확장합니다.
grep -e20180619 -e20180620 -e20180621 test
에서 검색할 수 있는 3가지 표현이 제공됩니다 e
.grep
test
아니면 이렇게 할 수도 있습니다:
printf '%s\n' 201806{19..21} | grep -f - test
표현식을 여러 줄 입력으로 전달합니다 (일부 구현의 경우 this 로 대체 grep
해야 할 수도 있음 )./dev/stdin
-
구체적으로 zsh
다음을 수행할 수도 있습니다.
numbers=({19..21} 25 31)
grep -E "201801(${(j:|:)numbers})" test
ERE로 사용할 수 있도록 (j:|:)
매개변수 확장 플래그를 사용하여 배열 요소를 (확장 정규식 대체 연산자)와 연결합니다.|
또는 다음을 사용하여 배열을 정규식 스칼라에 바인딩할 수 있습니다.
$ typeset -T re numbers '|'
$ numbers=({19..21} 25 31)
$ echo $re
19|20|21|25|31
정규식에는 일반적으로 숫자 범위 일치 기능이 없지만 zsh
패턴( extendedglob
기능적으로 정규식과 동일)은 <x-y>
연산자를 사용할 수 있습니다(십진수 시퀀스에만 해당).
print -rl -- ${(M)${(f)"$(<test)"}:#*201806<19-21>*}
답변3
따옴표가 없는 문자열은 명령을 실행하기 전에 쉘에 의해 해석됩니다. 귀하의 경우 시도 중인 명령은 다음으로 확장됩니다.grep 20180619 20180620 20180621 test
$ echo grep 201806{19..21} test
grep 20180619 20180620 20180621 test
한 가지 해결 방법은 정규식 대체를 지정하는 것입니다.
$ grep -E '201806(19|20|21)' test
20180619:
20180620:
20180621:
정규식을 사용하여 숫자 범위를 구성할 수 있지만 쉽지 않습니다. 바라보다https://www.regular-expressions.info/numericranges.html자세한 내용은
또 다른 옵션은 다음을 사용하는 것입니다.awk
$ awk -F: '$1>=20180619 && $1<=20180621' ip.txt
20180619:
20180620:
20180621:
여기서는 선을 분할 :
한 다음 첫 번째 필드를 $1
원하는 범위와 비교합니다.
답변4
POSIX쉘(아니요
bash
) 및 유틸리티:seq 20180618 20180624 | grep -f - test
-
numgrep '/20180618..20180624/' < test