Dateien im Verzeichnis mit einer bestimmten Zeichenfolge für den Namen zählen?


11

Ich habe folgende Dateien:

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

Ich möchte die Anzahl der Dateien zählen, snpderen Name das Wort (Groß- und Kleinschreibung beachten) enthält. Ich habe es versucht

grep -a 'snp' | wc -l   

aber dann wurde mir klar, dass grepin den Dateien gesucht wird. Was ist der richtige Befehl zum Durchsuchen der Dateinamen?


1
Haben Sie versucht, diese Site nach "Dateien zählen" zu durchsuchen?
don_crissti

Antworten:


17

Meinen Sie damit, nach dem Sie suchen möchten snpin den Dateinamen ? Das wäre ein einfacher Shell Glob (Wildcard), der wie folgt verwendet wird:

ls -dq *snp* | wc -l

Lassen Sie die -qFlagge weg, wenn Ihre Version von lssie nicht erkennt. Es behandelt Dateinamen mit "seltsamen" Zeichen (einschließlich Zeilenumbrüchen).


Ich war mir nicht sicher, ob ich lsDateinamen mit einem bestimmten Text abrufen könnte . Das hat aber funktioniert, danke.
Lucia O

@LuciaO lese deinen Kommentar noch einmal, es stimmt nicht lsmit den Dateinamen überein , es ist die Shell. lssieht eine Liste von Dateien, die dem Muster entsprechen; es ist nicht sehen , das Muster selbst.
Roaima

2
Beachten Sie, dass dies möglicherweise nicht funktioniert, wenn zu viele Dateien zurückgegeben werden.
Dennis Nolte

4

Wenn Sie ruhig in den Gängen von Unix & Linux stehen und genau zuhören, hören Sie eine gespenstische Stimme, die erbärmlich jammert: "Was ist mit Dateinamen, die Zeilenumbrüche enthalten?"

ls -d *snp* | wc -l

oder, in äquivalenter Weise ,

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

gibt alle Dateinamen aus, die snpjeweils eine neue Zeile enthalten, aber auch alle neuen Zeilen in den Dateinamen enthalten , und zählt dann die Anzahl der Zeilen in der Ausgabe. Wenn es eine Datei gibt, deren Name ist

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

dann wird dieser Name als ausgeschrieben

foosnp
bar.tsv

was natürlich als zwei Zeilen gezählt wird.

Es gibt einige Alternativen, die zumindest in einigen Fällen besser sind:

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

Das zählt die Zeilen, die enthalten snp, so dass das foosnp(\n)bar.tsvBeispiel von oben nur einmal zählt. Eine leichte Abweichung davon ist

ls -f | grep -c snp

Die beiden oben genannten Befehle unterscheiden sich darin:

  • Das ls -fwird Dateien enthalten, deren Namen mit beginnen .; printf … *Dies ist nicht der Fall, es sei denn, die dotglobShell-Option ist festgelegt.
  • printfist eine eingebaute Muschel; lsist ein externer Befehl. Daher lskönnten die etwas mehr Ressourcen verbrauchen.
  • Wenn die Shell a verarbeitet *, sortiert sie die Dateinamen. ls -fsortiert die Dateinamen nicht. Daher verbrauchen die lsmöglicherweise etwas weniger Ressourcen.

Aber sie haben etwas gemeinsam: Sie geben beide falsche Ergebnisse, wenn Dateinamen vorhanden sind, die Zeilenumbrüche enthalten und snpsowohl vor als auch nach dem Zeilenumbruch stehen .

Ein weiterer:

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

Dadurch wird eine Shell-Array-Variable erstellt, in der alle enthaltenen Dateinamen aufgelistet snpsind. Anschließend wird die Anzahl der Elemente im Array angegeben. Die Dateinamen werden als Zeichenfolgen und nicht als Zeilen behandelt, sodass eingebettete Zeilenumbrüche kein Problem darstellen. Es ist denkbar, dass dieser Ansatz ein Problem haben könnte, wenn das Verzeichnis sehr groß ist, da die Liste der Dateinamen im Shell-Speicher gespeichert werden muss.

Noch ein anderer:

Früher, als wir sagten printf "%s\n" *snp*, printfwiederholte (wiederverwendete) der Befehl die "%s\n"Formatzeichenfolge einmal für jedes Argument in der Erweiterung von *snp*. Hier nehmen wir eine kleine Änderung vor:

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

Dadurch wird die "%.0s\n"Formatzeichenfolge für jedes Argument in der Erweiterung von einmal wiederholt (wiederverwendet) *snp*. Bedeutet "%.0s"aber, die ersten Nullzeichen jeder Zeichenfolge zu drucken - dh nichts. Dieser printfBefehl gibt nur eine neue Zeile (dh eine leere Zeile) für jede Datei aus, die snpihren Namen enthält . und dann wc -lwerden sie zählen. Und wieder können Sie die .Dateien durch Festlegen einschließen dotglob.


1

Abstrakt:

Funktioniert für Dateien mit "ungeraden" Namen (einschließlich neuer Zeilen).

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

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

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

Beschreibung

Da ein einfacher Glob mit jedem Dateinamen snpin seinem Namen übereinstimmt, echo *snp*könnte ein einfacher für diesen Fall ausreichen, aber um wirklich zu zeigen, dass nur drei Dateien übereinstimmen, verwende ich:

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

Das einzige verbleibende Problem ist das Zählen der Dateien. Ja, grep ist eine übliche Lösung, und das Zählen neuer Zeilen mit wc -list auch eine übliche Lösung. Beachten Sie, dass grep -c(count) wirklich zählt, wie oft eine snpZeichenfolge übereinstimmt. Wenn ein Dateiname mehr als eine snpZeichenfolge enthält, ist die Anzahl falsch.

Wir können es besser machen.

Eine einfache Lösung besteht darin, die Positionsargumente festzulegen:

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

Um zu vermeiden, dass die Positionsargumente geändert werden, können wir jedes Argument in ein Zeichen umwandeln und die Länge der resultierenden Zeichenfolge drucken (für die meisten Shells):

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

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

Oder, um eine Unterschale zu vermeiden:

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

Dateiliste

Liste der Dateien (von der ursprünglichen Frage mit einer mit einem hinzugefügten Zeilenumbruch):

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' 

Das wird eine Datei mit einem Zeilenumbruch in der Mitte haben:

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

Und um die Glob-Expansion zu testen:

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

Dadurch wird ein Sternchen hinzugefügt, das, wenn es nicht in Anführungszeichen steht, auf die gesamte Liste der Dateien erweitert wird.


-1

Angenommen, Sie wollten die Anzahl der HTML-Dateien zählen:

ls | grep ".html" | wc -l

Wenn Sie also das Auftreten von "snp" zählen:

ls | grep "snp" | wc -l
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.