Đếm các tập tin trong thư mục với chuỗi cụ thể về tên?


12

Tôi có các tập tin sau:

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

Tôi muốn đếm số lượng tệp có từ snp(phân biệt chữ hoa chữ thường) trên tên của chúng. Tôi đã thử sử dụng

grep -a 'snp' | wc -l   

nhưng sau đó tôi nhận ra rằng grepcác tìm kiếm trong các tập tin. Lệnh chính xác để quét qua tên tệp là gì?


1
Bạn đã thử tìm kiếm trang web này cho "đếm tập tin"?
don_crissti

Câu trả lời:


18

Bạn có nghĩa là bạn muốn tìm kiếm snptrong tên tập tin ? Đó sẽ là một shell shell đơn giản (ký tự đại diện), được sử dụng như thế này:

ls -dq *snp* | wc -l

Bỏ -qcờ nếu phiên bản của lsbạn không nhận ra nó. Nó xử lý tên tệp chứa các ký tự "lạ" (bao gồm cả dòng mới).


Không chắc chắn nếu tôi có thể sử dụng lsđể truy xuất tên tệp với văn bản cụ thể trong đó. Điều đó làm việc mặc dù, cảm ơn.
Lucia O

@LuciaO đọc lại bình luận của bạn, nó không lskhớp với tên tệp, đó là vỏ. lsthấy một danh sách các tập tin phù hợp với mẫu; Nó không nhìn thấy mô hình chính nó.
roaima

2
lưu ý điều này có thể không hoạt động nếu bạn có quá nhiều tệp trở lại.
Dennis Nolte

4

Nếu bạn đứng lặng lẽ trên hành lang của Unix & Linux và lắng nghe một cách cẩn thận, bạn sẽ nghe thấy một giọng nói ma quái, khóc lóc thảm hại, Chuyện gì về tên tập tin có dòng mới?

ls -d *snp* | wc -l

hoặc, tương đương ,

printf "%s\n" *snp* | wc -l

sẽ xuất ra tất cả các tên tệp có chứa snp, mỗi tên được theo sau bởi một dòng mới, nhưng cũng bao gồm bất kỳ dòng mới nào trong tên tệp và sau đó đếm số lượng dòng trong đầu ra. Nếu có một tập tin có tên là

                                f o o s n p \n b a r . t s v

sau đó tên đó sẽ được viết thành

foosnp
bar.tsv

trong đó, tất nhiên, sẽ được tính là hai dòng.

Có một vài lựa chọn thay thế làm tốt hơn trong ít nhất một số trường hợp:

printf "%s\n" * | grep -c snp

trong đó đếm các dòng có chứa snp, vì vậy foosnp(\n)bar.tsvví dụ từ trên chỉ đếm một lần. Một biến thể nhỏ của điều này là

ls -f | grep -c snp

Hai lệnh trên khác nhau ở chỗ:

  • Di ls -fchúc sẽ bao gồm các tệp có tên bắt đầu bằng .; các printf … *không, trừ khi dotglobtùy chọn vỏ được thiết lập.
  • printflà một vỏ dựng sẵn; lslà một lệnh bên ngoài. Do đó, lscó thể sử dụng nhiều tài nguyên hơn một chút.
  • Khi shell xử lý a *, nó sắp xếp tên tệp; ls -fkhông sắp xếp tên tập tin. Do đó, lscó thể sử dụng ít tài nguyên hơn một chút.

Nhưng họ có một điểm chung: cả hai sẽ cho kết quả sai khi có tên tệp chứa dòng mới và có snpcả trước và sau dòng mới .

Khác:

filenamelist=(*snp*)
echo ${#filenamelist[@]}

Điều này tạo ra một biến mảng shell liệt kê tất cả các tên tệp có chứa snp, sau đó báo cáo số lượng phần tử trong mảng. Tên tệp được coi là chuỗi, không phải dòng, vì vậy dòng mới được nhúng không phải là vấn đề. Có thể hình dung rằng cách tiếp cận này có thể có vấn đề nếu thư mục rất lớn, vì danh sách tên tệp phải được giữ trong bộ nhớ shell.

Còn nữa:

Trước đó, khi chúng ta nói printf "%s\n" *snp*, printflệnh lặp lại (sử dụng lại) "%s\n"chuỗi định dạng một lần cho mỗi đối số trong việc mở rộng *snp*. Ở đây, chúng tôi thực hiện một thay đổi nhỏ trong đó:

printf "%.0s\n" *snp* | wc -l

Điều này sẽ lặp lại (tái sử dụng) "%.0s\n"chuỗi định dạng một lần cho mỗi đối số trong việc mở rộng *snp*. Nhưng "%.0s"có nghĩa là in các ký tự 0 đầu tiên của mỗi chuỗi - tức là không có gì. Đây printflệnh chí đầu ra chỉ một dòng mới (ví dụ, một dòng trống) cho mỗi tập tin có chứa snptrong tên của nó; và sau đó wc -lsẽ đếm chúng. Và, một lần nữa, bạn có thể bao gồm các .tệp bằng cách cài đặt dotglob.


1

Trừu tượng:

Hoạt động cho các tệp có tên "lẻ" (bao gồm các dòng mới).

set -- *snp* ; echo "$#"                             # change positional arguments

count=$(printf 'x%.0s' *snp*); echo "${#count}"      # most shells

printf -v count 'x%.0s' *snp*; echo "${#count}"      # bash

Sự miêu tả

Vì một quả cầu đơn giản sẽ khớp với mọi tên tệp với snptên của nó, một đơn giản echo *snp*có thể đủ cho trường hợp này, nhưng để thực sự chỉ ra rằng chỉ có ba tệp phù hợp với tôi sẽ sử dụng:

$ ls -Q *snp*
"Codigo-0275_tdim.snps.tsv"  "foo * bar\tsnp baz.tsv"  "S134_tdim.snps.tsv"

Vấn đề duy nhất còn lại là đếm các tập tin. Có, grep là một giải pháp thông thường và có, đếm các dòng mới wc -lcũng là một giải pháp thông thường. Lưu ý rằng grep -c(đếm) thực sự đếm số lần một snpchuỗi được khớp và nếu một tên tệp có nhiều hơn một snpchuỗi trong tên, thì số đếm sẽ không chính xác.

Chúng ta có thể làm tốt hơn.

Một giải pháp đơn giản là đặt các đối số vị trí:

$ set -- *snp*
$ echo "$#"
3

Để tránh thay đổi các đối số vị trí, chúng ta có thể chuyển đổi từng đối số thành một ký tự và in độ dài của chuỗi kết quả (đối với hầu hết các shell):

$ printf 'x%.0s' *snp*
xxx

$ count=$(printf 'x%.0s' *snp*); echo "${#count}"
3

Hoặc, trong bash, để tránh một subshell:

$ printf -v count 'x%.0s' *snp*; echo "${#count}"
3

Danh sách tập tin

Danh sách các tệp (từ câu hỏi ban đầu với một dòng có thêm dòng mới):

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' 

Điều đó sẽ có một tập tin với một dòng mới ở giữa:

f o o s n p \n b a r . t s v

Và để kiểm tra mở rộng toàn cầu:

$ touch $'foo * bar\tsnp baz.tsv'

Điều đó sẽ thêm một dấu sao, nếu không được trích dẫn, sẽ mở rộng ra toàn bộ danh sách các tệp.


-1

giả sử bạn muốn đếm số lượng tệp html:

ls | grep ".html" | wc -l

vì vậy nếu bạn đang đếm số lần xuất hiện của "snp":

ls | grep "snp" | wc -l
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.