grep 구문의 시작 부분이나 끝 부분에 와일드카드가 배치될 때 왜 다르게 작동합니까? [복사]

grep 구문의 시작 부분이나 끝 부분에 와일드카드가 배치될 때 왜 다르게 작동합니까? [복사]

예를 들어, 현재 디렉터리에 특정 확장자를 가진 파일이 몇 개 있는지 계산하고 싶습니다.

나는 다음을 사용했다:

ls | grep ".txt" | wc -l

이는 다음과 같이 작동합니다.

ls | grep ".txt*" | wc -l

그런데 왜 이것도 작동하지 않습니까?

ls | grep "*.txt" | wc -l

확장 앞에 와일드카드를 사용할 때 grep 표현식에서 작동하지 않는 것 같은 이유는 무엇입니까? 왜 마지막에는 작동하지 않나요?(모든 txt 파일은 .txt로 끝나기 때문에 .txt.zip과 같은 형식이면 작동하지 않는 것 같아요)?

답변1

$ ls *.txt

이 명령은 쉘 글로빙을 사용하여 로 시작하는 모든 이름을 나열합니다 .txt.

$ ls | grep "*.txt"

이 명령은 현재 작업 디렉토리에 있는 모든(숨겨지지 않은) 파일을 나열하고 해당 출력을 로 보냅니다 grep. 이는 정규 표현식을 기반으로 하는 파일 이름과 일치합니다 /*.txt/.

/*.txt/

이 정규식은 사용되는 정규식의 스타일에 따라 다음 패턴과 일치할 수 있습니다.

*    -- zero or more characters of any type (or possibly only a literal '*'), followed by
.    -- exactly one character of any type, followed by 
txt  -- the literal string 'txt', followed by anything

정규식에서 *"0개 이상의 선행 하위 표현식"을 나타내는 와일드카드이지만 쉘 glob 와일드카드와는 다르게 작동합니다. 관련하여 .이는 마침표가 아니며 한 문자의 와일드카드입니다( ?셸 글로브의 와일드카드와 유사). 따라서 이 표현식은 (역시 정규 표현식의 스타일에 따라) file.txt, , sometxtfile중 하나와 일치 photo_of_a_txt_file.png하지만 실제로는 일치하지 않습니다 txtfile(이전 문자가 와 일치하지 않기 때문입니다 txt). 따라서 txt이 정규식을 사용하면 파일 이름의 시작 부분을 제외하고 리터럴 문자열이 어디에나 나타날 수 있다는 점을 아는 것이 중요합니다 .

.txt다음으로 끝나는 파일 이름을 캡처하는 더 나은 정규식 /\.txt$/:

\.  -- A literal .
txt -- The literal string 'txt'
$   -- End of input

ls따라서 파이핑 을 고집한다면 grep(파싱된 출력이 왜 나쁜 생각인지 설명하는 책을 지금 당장 읽지 마십시오 ls) 아마도 다음과 같이 할 것입니다.

$ ls | grep "\.txt$"

을 사용하는 경우에는 wc그렇게 할 필요가 없습니다. grep셀 수 있습니다:

$ ls | grep -c "\.txt$"

관련 정보