예를 들어, 현재 디렉터리에 특정 확장자를 가진 파일이 몇 개 있는지 계산하고 싶습니다.
나는 다음을 사용했다:
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$"