นับจำนวนไฟล์ในไดเรกทอรีที่มีสตริงชื่อเฉพาะหรือไม่


12

ฉันมีไฟล์ต่อไปนี้:

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
คุณลองค้นหา "count files" ในเว็บไซต์นี้หรือไม่?
don_crissti

คำตอบ:


18

คุณหมายถึงคุณต้องการค้นหาsnpในชื่อไฟล์หรือไม่? นั่นจะเป็นเชลล์แบบง่ายๆ (wildcard) ใช้แบบนี้:

ls -dq *snp* | wc -l

งดการ-qตั้งค่าสถานะถ้ารุ่นของคุณlsไม่รู้จัก มันจัดการชื่อไฟล์ที่มีอักขระ "แปลก" (รวมถึงบรรทัดใหม่)


ไม่แน่ใจว่าฉันสามารถใช้lsเพื่อเรียกชื่อไฟล์ด้วยข้อความที่ระบุในพวกเขาหรือไม่ ที่ทำงานแม้ว่าขอบคุณ
Lucia O

@LuciaO อ่านความคิดเห็นของคุณใหม่ไม่ใช่ชื่อlsที่ตรงกับชื่อมันคือเชลล์ lsเห็นรายการไฟล์ที่ตรงกับรูปแบบ มันไม่เห็นรูปแบบของตัวเอง
roaima

2
โปรดทราบว่านี่อาจไม่ทำงานหากคุณมีไฟล์ที่ส่งคืนมากเกินไป
Dennis Nolte

4

หากคุณยืนเงียบ ๆ ในโถงทางเดินของ Unix & Linux และตั้งใจฟังคุณจะได้ยินเสียงที่น่าสยดสยองคร่ำครวญอย่างน่าสงสาร

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" *snp*แต่"%.0s"หมายถึงการพิมพ์อักขระศูนย์แรกของแต่ละสตริง - เช่นไม่มีอะไร printfคำสั่งนี้จะแสดงเฉพาะบรรทัดใหม่ (เช่นบรรทัดว่าง) สำหรับแต่ละไฟล์ที่มีsnpในชื่อ แล้วwc -lจะนับพวกเขา และอีกครั้งที่คุณสามารถรวมไฟล์โดยการตั้งค่า.dotglob


1

บทคัดย่อ:

ใช้งานได้กับไฟล์ที่มีชื่อ "คี่" (รวมถึงบรรทัดใหม่)

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

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

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

ลักษณะ

เนื่องจาก glob ที่เรียบง่ายจะตรงกับชื่อไฟล์ทุกชื่อsnpในชื่อของมันecho *snp*จะง่ายพอสำหรับกรณีนี้ แต่เพื่อแสดงให้เห็นว่าจริงๆมีเพียงสามไฟล์ที่ตรงกับที่ฉันจะใช้:

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

ปัญหาเดียวที่เหลืออยู่คือการนับไฟล์ ใช่ grep เป็นคำตอบปกติและใช่การนับบรรทัดใหม่ด้วยwc -lเป็นวิธีแก้ปัญหาปกติ โปรดทราบว่าgrep -c(นับ) นับจำนวนจริง ๆ ที่snpจับคู่สตริงและถ้าชื่อไฟล์หนึ่งชื่อมีมากกว่าหนึ่งsnpสตริงในชื่อการนับจะไม่ถูกต้อง

เราทำได้ดีกว่า

ทางออกหนึ่งที่ง่ายคือการตั้งค่าอาร์กิวเมนต์ตำแหน่ง:

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

เพื่อหลีกเลี่ยงการเปลี่ยนอาร์กิวเมนต์ตำแหน่งเราสามารถเปลี่ยนอาร์กิวเมนต์แต่ละตัวให้เป็นอักขระหนึ่งตัวและพิมพ์ความยาวของสตริงผลลัพธ์ (สำหรับเชลล์ส่วนใหญ่):

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

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

หรือในทุบตีเพื่อหลีกเลี่ยงการ subshell:

$ 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

และเพื่อทดสอบการขยายตัวของ glob:

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

ที่จะเพิ่มเครื่องหมายดอกจันหากไม่ได้อ้างอิงจะขยายไปยังรายการไฟล์ทั้งหมด


-1

สมมติว่าคุณต้องการนับจำนวนไฟล์ html:

ls | grep ".html" | wc -l

ดังนั้นหากคุณนับจำนวน "snp":

ls | grep "snp" | wc -l
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.