Wie drucke ich Dateiinhalte nur, wenn die erste Zeile einem bestimmten Muster entspricht?

11

Ich schreibe ein Skript und möchte überprüfen, ob die erste Zeile der Datei mit einem bestimmten Muster übereinstimmt. Wenn dies der Fall ist, wird die Datei ausgedruckt. Wie kann ich das erreichen?

Wie überprüfe ich das Muster? Gibt es eine Möglichkeit, nach Mustern zu suchen und basierend auf der Ausgabe etwas zu tun?

BEARBEITEN: Bitte werfen Sie einen Blick auf diese Frage: /programming/5536018/how-to-get-match-regex-pattern-using-awk-from-file

Ich möchte so etwas, aber keiner von ihnen hat für mich gearbeitet. Grundsätzlich möchte ich überprüfen, ob die erste Zeile mit einem Regex-Muster übereinstimmt oder nicht, und auf dieser Grundlage die Dateizeilen drucken.

Mathew
quelle
1
Was ist die Ausgabe, die Sie erwarten? Nach welchem ​​Muster suchen Sie? Was hast du bisher versucht?
Tachomi
@tachomi bearbeitet bitte werfen Sie einen Blick
Mathew

Antworten:

17

Sie könnten das tun mit ed:

ed -s infile <<\IN 2>/dev/null
1s/PATTERN/&/
,p
q
IN

Der Trick hier ist , um zu versuchen zu ersetzen PATTERNauf 1stLinie mit sich selbst. edwird ein Fehler ausgegeben, wenn das angegebene Muster nicht gefunden werden kann. Die ,pgesamte Datei (Drucken der gesamten Datei) wird nur ausgeführt, wenn dies 1s/PATTERN/&/erfolgreich ist.

Oder mit sed:

sed -n '1{
/PATTERN/!q
}
p' infile

Dies qgilt, wenn die erste Zeile nicht ( !) übereinstimmt PATTERN, andernfalls pwerden alle Zeilen gedruckt.
Oder, wie Toby Speight betonte , mit GNU sed:

sed '1{/PATTERN/!Q}' infile

Qist das gleiche wie, qaber es druckt nicht den Musterraum.

don_crissti
quelle
Sie könnten Qstatt qfür GNU sed oder dvorher q(portabel), um das -nFlag und den pBefehl nicht zu benötigen : sed '1{/PATTERN/!Q}' infileoder sed -e '1{' -e '/PATTERN/!{' -e 'd' -e 'q' -e '}' -e '}' infile.
Toby Speight
dstartet den Befehlszyklus neu Das fängt mich immer auf! : - |
Toby Speight
Bei GNU beschwert sich sedder erste sedBefehl sed: -e expression #1, char 10: extra characters after command(wegen der p), aber die edund die letzten sedVorschläge funktionieren einwandfrei.
Skippy le Grand Gourou
NB: Lösungen, die durch diese Antwort bereitgestellt werden, haben gegenüber anderen Antworten den Vorteil, dass sie auf ein Rohr angewendet werden können.
Skippy le Grand Gourou
1
@ SkippyleGrandGourou - Sie haben versucht, es in einen Einzeiler zu verwandeln, ohne die Befehle durch Semikolons zu trennen - dies ist der richtige Weg, dies zu tunsed -n '1{/PATTERN/!q};p'
don_crissti
15

Mit POSIX Tools Brust:

{ head -n 1 | grep pattern && cat; } <file
cuonglm
quelle
1
{double} <süß.
Mikeserv
@mikeserv: Ich beabsichtige, es zu verwenden, um zu verhindern, dass neue Personen verwirrt werden, aber Stephane bearbeitet ist klarer.
Cuonglm
8
 awk '/pattern/{print FILENAME}; {nextfile}' ./*.txt

würde den Namen der nicht ausgeblendeten txtDateien im aktuellen Verzeichnis drucken, dessen erste Zeile dem erweiterten regulären Ausdruck patternmit den unterstützten awkImplementierungen entsprichtnextfile .

Wenn Sie anstelle des Dateinamens den gesamten Dateiinhalt drucken möchten, haben Sie folgende Möglichkeiten:

 awk 'FNR == 1 && ! /pattern/ {nextfile}; {print}' ./*.txt

Dies ist insofern effizient, als nur ein Befehl ausgeführt wird. Da es sich jedoch awknicht um den effizientesten Befehl zum Speichern des Inhalts einer Datei handelt, können Sie bei großen Dateien möglicherweise bessere Leistungen erzielen, indem Sie Folgendes tun:

 awk '/pattern/{printf "%s\0", FILENAME}; {nextfile}' ./*.txt |
   xargs -r0 cat

Verwenden Sie awkdiese Option nur , um die Liste der übereinstimmenden Dateien (durch 0 getrennt) zu drucken und sich darauf catzu verlassen , dass deren Inhalt ausgegeben wird.

Stéphane Chazelas
quelle
6

Wenn Sie ein Shell-Skript schreiben, könnten Sie so etwas wie

for file in ./*; do head -n 1 "$file" | grep -q 'PATTERN' && cat "$file"; done

Oder in Perl:

perl -Tlne '$f = /PATTERN/ if $. == 1; print if $f; $. = 0 if eof' ./*
terdon
quelle
@ Stéphane Chazelas: Vielleicht close ARGVist mehr Redewendung als zuzuweisen $..
Cuonglm
@terdon Yours sieht aus wie Code Golf, alles in einer Zeile, keine Klammern um die Variablennamen und fördert keine saubere Struktur. Und Sie hatten ein fehlendes Dollarzeichen, als ich gepostet habe, das ist einfach nicht die Art, Bash zu lehren. Ich gehe davon aus, dass diese Faktoren aus dem Perl-Hintergrund stammen, den Sie anscheinend auch haben, also wird Ihnen vergeben! ;)
@guest hallo und willkommen auf der Seite! Ich habe Ihre Antwort in einen Kommentar umgewandelt, da Antworten nur veröffentlicht werden sollten, wenn sie die eigentliche Frage beantworten. Dies ist kein Forum im klassischen Sinne und wir wollen hier nur reine Fragen und Antworten. Vielleicht möchten Sie einen Blick in die Hilfe werfen oder die Tour machen , um die Site besser zu verstehen. Das heißt, mein Hintergrund ist eigentlich in der Biologie, also ja, mein Code ist alles andere als sauber :) Ich sehe jedoch nicht, wie Klammern hier helfen würden, die Anführungszeichen schützen die Variable bereits. Was würde dies brechen, vor dem Klammern schützen würden?
Terdon
@guest ah, sorry, habe vergessen, dass du keinen Kommentar abgeben kannst. Fühlen Sie sich frei zu kommen und zu erklären Chat zu , ich bin sicher, ich könnte etwas lernen.
Terdon
5

Oldschool, übersetzen Sie einfach Ihren Satz in Standardbefehle:

for file in *; do
    if head -n 1 "${file}" | grep -q 'PATTERN'; then
        cat "${file}"
    fi
done

Für das Lernen von Bash ist das ein guter Anfang. Wenn Sie nur eine schnelle Lösung benötigen, probieren Sie die sed-, awk- oder perl-Antworten aus. Beide sind nett, aber sie sind eigene Sprachen, die Sie lernen müssen (und wahrscheinlich wollen).

Es ist ein ziemlich einfaches Beispiel. Wenn Sie also mehr erfahren möchten, können Sie dasselbe auch in Ruby, PHP, JS (z. B. in NodeJS) oder einer anderen Sprache versuchen, die den Dateizugriff ermöglicht. Selbst C / C ++ oder Java sollte mit einer kleinen Aufgabe einfach zu verwalten sein.

Gast
quelle
1
Dies ist im Grunde das gleiche wie meins, außer dass Sie if/elseanstelle von verwenden [ ] &&.
Terdon