다음 파일이 있습니다.
Codigo-0275_tdim.matches.tsv
Codigo-0275_tdim.snps.tsv
FloragenexTdim_haplotypes_SNp3filter17_single.tsv
FloragenexTdim_haplotypes_SNp3filter17.tsv
FloragenexTdim_SNP3Filter17.fas
S134_tdim.alleles.tsv
S134_tdim.snps.tsv
S134_tdim.tags.tsv
snp
이름에 단어가 포함된 파일 수를 계산하고 싶습니다(대소문자 구분). 나는 사용하려고
grep -a 'snp' | wc -l
그런데 grep
파일 내에서 검색한다는 것을 깨달았습니다. 파일 이름을 검색하는 올바른 명령은 무엇입니까?
답변1
snp
파일 내에서 검색한다는 의미입니다.이름? 이는 다음과 같이 사용되는 간단한 쉘 글로브(와일드카드)입니다.
ls -dq *snp* | wc -l
-q
ls
귀하의 버전이 이 플래그를 인식하지 못하는 경우 이 플래그를 무시하십시오. "이상한" 문자(개행 문자 포함)가 포함된 파일 이름을 처리합니다.
답변2
유닉스와 리눅스 복도에 조용히 서서 주의 깊게 들어보면, "파일 이름에 개행 문자가 포함되어 있으면 어쩌지?"라는 애처롭게 울부짖는 유령 같은 목소리가 들릴 것이다.
ls -d *snp* | wc -l
또는,같이,
printf "%s\n" *snp* | wc -l
포함된 모든 파일 이름을 출력하며 snp
각 파일 이름 뒤에 개행 문자가 옵니다.
파일 이름에 줄 바꿈도 포함됩니다.를 누른 다음 출력의 행 수를 계산합니다. 이름의 파일이 있는 경우
f o o s n p \n b a r . t s v
그러면 이름은 다음과 같이 쓰여질 것이다.
foosnp
bar.tsv
물론 이것은 두 줄로 간주됩니다.
적어도 어떤 경우에는 더 잘 작동하는 대안이 있습니다.
printf "%s\n" * | grep -c snp
포함된 행을 계산하므로 snp
위 foosnp(\n)bar.tsv
의 예에서는 한 번만 계산합니다. 이에 대한 약간 다른 접근 방식은 다음과 같습니다.
ls -f | grep -c snp
위 두 명령의 차이점은 다음과 같습니다.
ls -f
이름이 ;로 시작하는 파일이 포함 됩니다.
. 쉘 옵션이 설정되지printf … *
않는 한 그렇지 않습니다.dotglob
printf
내장 쉘은ls
외부 명령입니다. 따라서ls
약간 더 많은 리소스가 사용될 수 있습니다.- 쉘은 a 를 처리할 때
*
파일 이름을 정렬하지만ls -f
파일 이름은 정렬하지 않습니다. 따라서ls
약간 적은 양의 리소스가 사용될 수 있습니다.
그러나 공통점이 있습니다. 파일 이름에 개행 문자가 포함되어 있으면 둘 다 잘못된 결과를 제공합니다.snp
개행 문자 앞과 뒤 모두.
다른:
filenamelist=(*snp*)
echo ${#filenamelist[@]}
이는 쉘 배열 변수를 생성하고 포함된 모든 파일 이름을 나열한 snp
다음 배열의 요소 수를 보고합니다. 파일 이름은 줄이 아닌 문자열로 처리되므로 삽입된 줄 바꿈은 문제가 되지 않습니다. 상상할 수 있듯이, 파일 이름 목록이 쉘 메모리에 보관되어야 하기 때문에 디렉토리가 큰 경우 이 접근 방식은 문제를 일으킬 수 있습니다.
그 후에는 다음이 있습니다.
앞에서 언급한 대로 명령은 printf "%s\n" *snp*
확장의 각 매개변수에 대해 printf
형식 문자열을 한 번씩 반복(재사용)합니다 . 여기서는 작은 변화를 줍니다:"%s\n"
*snp*
printf "%.0s\n" *snp* | wc -l
그러면 "%.0s\n"
.extension의 각 매개변수에 대해 형식 문자열이 한 번씩 반복(재사용) 됩니다 *snp*
. 그러나 "%.0s"
각 문자열의 처음 0 문자를 인쇄하는 것을 의미합니다. 즉, 아무것도 인쇄하지 않습니다. 이 명령은 printf
이름에 포함된 각 파일에 대해 하나의 개행 문자(즉, 빈 줄)만 출력한 snp
다음 wc -l
계산됩니다. 그리고 .
설정을 통해 이러한 파일을 포함 할 수 있습니다 dotglob
.
답변3
추상적인:
"이상한" 이름(개행 포함)을 가진 파일에 대해 작동합니다.
set -- *snp* ; echo "$#" # change positional arguments
count=$(printf 'x%.0s' *snp*); echo "${#count}" # most shells
printf -v count 'x%.0s' *snp*; echo "${#count}" # bash
설명하다
snp
간단한 glob은 이름에 있는 모든 파일 이름 과 일치하므로 echo *snp*
이 경우에는 간단한 파일이면 충분하지만 실제로 세 개의 파일만 일치하는지 보여주기 위해 다음을 사용하겠습니다.
$ ls -Q *snp*
"Codigo-0275_tdim.snps.tsv" "foo * bar\tsnp baz.tsv" "S134_tdim.snps.tsv"
남은 유일한 문제는 파일 수를 세는 것입니다. 예, grep은 일반적인 솔루션이며, 예, 새 줄을 세는 것이 wc -l
일반적인 솔루션입니다. (count) 는 grep -c
실제로 문자열이 일치하는 횟수를 계산하며 snp
, 파일 이름 이름에 둘 이상의 snp
문자열이 포함되어 있으면 개수가 올바르지 않습니다.
우리는 더 잘할 수 있습니다.
간단한 해결책은 위치 매개변수를 설정하는 것입니다.
$ set -- *snp*
$ echo "$#"
3
위치 인수 변경을 방지하기 위해 각 인수를 문자로 변환하고 결과 문자열의 길이를 인쇄할 수 있습니다(대부분의 쉘에서):
$ printf 'x%.0s' *snp*
xxx
$ count=$(printf 'x%.0s' *snp*); echo "${#count}"
3
또는 bash에서는 서브셸을 사용하지 마세요.
$ printf -v count 'x%.0s' *snp*; echo "${#count}"
3
파일 목록
파일 목록(줄바꿈이 추가된 원래 질문에서 발췌):
a='
Codigo-0275_tdim.matches.tsv
Codigo-0275_tdim.snps.tsv
FloragenexTdim_haplotypes_SNp3filter17_single.tsv
FloragenexTdim_haplotypes_SNp3filter17.tsv
FloragenexTdim_SNP3Filter17.fas
S134_tdim.alleles.tsv
S134_tdim.snps.tsv
S134_tdim.tags.tsv'
$ touch $a
touch $'foosnp\nbar.tsv'
중간에 개행 문자가 있는 파일이 생성됩니다.
f o o s n p \n b a r . t s v
그리고 전역 확장을 테스트합니다.
$ touch $'foo * bar\tsnp baz.tsv'
별표가 추가되어 따옴표를 사용하지 않으면 전체 파일 목록으로 확장됩니다.
답변4
html 파일의 수를 세고 싶다고 가정해 보겠습니다.
ls | grep ".html" | wc -l
따라서 "snp" 발생 횟수를 계산하려면 다음을 수행하세요.
ls | grep "snp" | wc -l