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.tsv
ví 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 -f
chúc sẽ bao gồm các tệp có tên bắt đầu bằng .
; các printf … *
không, trừ khi dotglob
tùy chọn vỏ được thiết lập.
printf
là một vỏ dựng sẵn; ls
là một lệnh bên ngoài. Do đó, ls
có 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 -f
không sắp xếp tên tập tin. Do đó, ls
có 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ó snp
cả 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*
, printf
lệ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 printf
lệ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 snp
trong tên của nó; và sau đó wc -l
sẽ đế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
.