2014-06-05 10 views
6

Ich habe versucht, die Skripte zu machen, die ich schreibe einfacher und einfacher.Leicht zählen Wörter in einer Liste von Dateien in einem Ordner nach grep -v Befehl

Es gibt zahlreiche Möglichkeiten zum Schreiben die Anzahl der Wörter aller Dateien in einem Ordner oder sogar alle Dateien von Unterverzeichnissen eines Ordners zu erhalten.

Zum Beispiel könnte ich

wc */* 

schreiben, und ich könnte Ausgabe wie folgt (dies ist die gewünschte Ausgabe) erhalten:

0  0  0 10.53400000/YRI.GS000018623.NONSENSE.vcf 
    0  0  0 10.53400000/YRI.GS000018623.NONSTOP.vcf 
    0  0  0 10.53400000/YRI.GS000018623.PFAM.vcf 
    0  0  0 10.53400000/YRI.GS000018623.SPAN.vcf 
    0  0  0 10.53400000/YRI.GS000018623.SVLEN.vcf 
    2  20  624 10.53400000/YRI.GS000018623.SVTYPE.vcf 
    2  20  676 10.53400000/YRI.GS000018623.SYNONYMOUS.vcf 
    13  130  4435 10.53400000/YRI.GS000018623.TSS-UPSTREAM.vcf 
425  4250 126381 10.53400000/YRI.GS000018623.UNKNOWN-INC.vcf 

aber wenn es zu viele Dateien sind, könnte ich bekommen eine Fehlermeldung wie diese:

-bash: /usr/bin/wc: Argument list too long 

so könnte ich eine Variable machen und einen Ordner nach dem anderen machen, so:

while read $FOLDER 
do 
    wc $FOLDER/* >> outfile.txt 
done < "$FOLDER_LIST" 

so geht das von einer Zeile bis 5 einfach so.

Ferner wird in einem Fall möchte ich grep -v zuerst verwenden, dann carryout das Wort zählen, etwa so:

grep -v dbsnp */* | wc 

aber dies würde von zwei Fehlern leiden:

  1. Argumentliste zu lang
  2. Wenn es nicht zu lang wäre, würde es das wc für alle Dateien auf einmal geben, nicht pro Datei.

also rekapitulieren, würde ich gerne dieses in der Lage sein zu tun:

grep -v dbsnp */* wc > Outfile.txt 
awk '{print $4,$1} Outfile.txt > Outfile.summary.txt 

und es hat Rückkehr ausgegeben, wie ich oben zeigte.

Gibt es eine sehr einfache Möglichkeit, dies zu tun? Oder schaue ich mir wenigstens eine Schleife an? Ich kenne 101 Möglichkeiten, dies genauso zu tun wie der Rest von uns mit einem 4-10 Zeilen Skript, aber ich würde gerne in der Lage sein, einfach 2 Liner in die Eingabeaufforderung einzugeben ... und mein Wissen über die Shell ist noch nicht tief genug, um zu wissen, welche Wege erlauben würden, was ich vom OS verlangen würde.

EDIT -

Eine Lösung vorgeschlagen wurde:

find -exec grep -v dbsnp {} \; | xargs -n 1 wc 

Diese Lösung der folgenden Ausgabe führt:

wc: 1|0:53458644:AMBIGUOUS:CCAGGGC|-16&GCCAGGGCCAGGGC|-18&GCCAGGGCC|-19&GGCCAGGGC|-19&GCCAGGGCG|-19,.:48:48,48:4,4:0,17:-48,0,-48:0,0,-17:27:3,24:24: No such file or directory 
wc: 10: No such file or directory 
wc: 53460829: No such file or directory 
wc: .: Is a directory 
     0  0  0 . 
wc: AA: No such file or directory 
wc: CT: No such file or directory 
wc: .: Is a directory 
     0  0  0 . 
wc: .: Is a directory 
     0  0  0 . 

so nahe wie ich sagen kann, die Behandlung jeder Zeile zu sein scheint als eine Datei. Ich überprüfe immer noch die anderen Antworten und danke für Ihre Hilfe.

Antwort

3

Sie haben erwähnt, dass „dies löst nicht das Problem, das WC in einem der Rückkehr Artikel-für-Artikel Mode“

Nach Willen:

find -exec wc {} \; 

Aber das wird nicht kommen mit Ihrem grep Filter "grep -v"

wenn Sie beabsichtigen, das gleiche zu tun wie mein Kommentar zu dieser Antwort angezeigt, dann prüfen Sie bitte folgende Arbeiten für Sie:

find -exec bash -c "echo -n {}; grep -v dbsnp {} | wc " \; 
+0

@Vincent Ich konnte den Zweck nicht verstehen mit 'grep -v', Wenn du ein wenig darauf eingehen kannst, können wir versuchen, eine Lösung um sie herum zu bauen.Sie benutzen 'grep -v', es schließt alle Zeilen aus, die' dbsnp enthalten ', und zählen Sie die Wörter, oder Sie möchten nur aus der Wortzahl dbsnp ausschließen? – PradyJord

+0

Ich möchte die gesamte Zeile ausschließen, und Ich sollte hinzufügen, ich bin eigentlich Ziel, wc -l Dies funktioniert und hatte die beabsichtigte Wirkung (alle anderen Antworten tatsächlich fehlgeschlagen - danke !!!) –

+0

überprüfen Sie bitte 2. finden – PradyJord

2

Sie haben zu viele Übereinstimmungen mit dem */*, also erhält Grep eine lange Argumentliste.Sie können find verwenden, um dies zu umgehen:

find -exec grep -v dbsnp {} \; | wc 

und vielleicht möchten Sie auch von möglichen Traversal Fehler loszuwerden:

find -exec grep -v dbsnp {} \; 2> /dev/null | wc 
+0

Dies ist sehr interessant. Warum tut WC Fehler, aber nicht finden? Wie kann ich solche Dinge lernen, die Sie anscheinend kennen, aber ich nicht? Ich sehe diese Information nicht auf der Manpage für wc. Dies löst auch nicht das Problem, das WC Stück für Stück zurückzugeben; eher gibt es nur die Summe zurück. –

+0

@VincentLaufer Sie möchten über 'ARG_MAX' [hier] lesen (http://www.in-ulm.de/~masheck/various/argmax/). 'find -exec' wurde entwickelt, um dies zu umgehen, indem es in Mengen aggregiert wird, die in' ARG_MAX' passen (siehe [hier] (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/find.html): * " Die Größe eines Satzes von zwei oder mehr Pfadnamen muss so begrenzt sein, dass die Ausführung des Dienstprogramms nicht dazu führt, dass der Grenzwert {ARG_MAX} des Systems überschritten wird. "*. –

0

Basierend auf perreal's Antwort:

Wenn Sie die wc Datei für Datei möchten, können Sie xargs verwenden:

find -exec grep -v dbsnp {} \; | xargs -n 1 wc 

xargs können die Standardeingabe lesen und bauen und Befehlszeilen mit ausführen. So liest es das Ergebnis Ihres Eingabestroms und führt wc für jeden einzelnen Artikel (-n 1) aus.

+2

Ihr zweites Beispiel unterliegt ebenso wie AR ARM_MAX "wc */*' ist so, dass es auch nicht funktioniert, wenn die Glob-Erweiterung zu groß ist. –

+0

Du hast recht. Okay, er sollte mit 'find' gehen, dann ... –