grep mit Zeilenumbruch

FatManStanding

Lt. Junior Grade
Registriert
Aug. 2021
Beiträge
497
Hallo,

ich möchte eine mehrzeilige Variable prüfen ob ein bestimmtes Muster in einer bestimmten Reihe von Zeilen vorkommt, z. B. ob in

Code:
1
2
3
4
5
100

min. 5 aufeinanderfolgende Zeilen eine einstelle Zahl unter 50 haben. Ich dachte da an 'grep' in etwa sowas:

Code:
echo "$var" | grep ^[0-4][0-9]$\n^[0-4][0-9]$\n^[0-4][0-9]$\n^[0-4][0-9]$\n^[0-4][0-9]$

geht aber nicht. Habe auch einfachere Varianten (z. B. nur ^[0-9]$) versucht, das Problem scheint der Zeilenumbruch zu sein. Habe diverse Vorschläge gefunden, dass man Perl-Regex (Option -P) einschalten muss, alles kein Erfolg.

Falls jemand eine andere Lösung hat statt grep bin ich flexibel.
 
was meinst du mit geht nicht? dein Pattern nutzt [0-4][0-9], also muss ja jede Zahl 2 Ziffern haben. Das ist in deinem Beispiel ja nicht der Fall
Ergänzung ()

FatManStanding schrieb:
eine einstelle Zahl unter 50
ist auch nicht so klar formuliert. Soll das "einstellige Zahl" sein? Also 0-9 dann? Warum dann "unter 50"? Meinst du damit "5 einstellige Zahlen direkt unter der Zahl 50"?

Ich denke ich verstehe das Problem einfach falsch, Fakt ist aber grep -P matcht eigentlich auch Zeilenumbruch
 
Zuletzt bearbeitet:
Ich habe

test.txt
Code:
1
2
3
4
5
100

und test.sh
Code:
#!/bin/bash

value=`cat test.txt`
echo "print..."
echo "$value"

echo "grep 1..."
echo "$value" | grep -o 5

echo "grep 2..."
echo "$value" | grep -o ^[0-4][0-9]

Die Ausgabe wäre
Code:
$ bash test.sh
print...
1
2
3
4
5
100
grep 1...
5
grep 2...
10
Meinst du so was?
 
  • Gefällt mir
Reaktionen: GTrash81
Code:
if echo "$var" | grep -E '^[0-4][0-9]$' -A4 | grep -E '^[0-4][0-9]$' -A3 | grep -E '^[0-4][0-9]$' -A2 | grep -E '^[0-4][0-9]$' -A1 | grep -E '^[0-4][0-9]$'; then
    echo "Mindestens 5 aufeinanderfolgende Zeilen haben eine Zahl unter 50."
else
    echo "Es gibt nicht genug aufeinanderfolgende Zeilen mit einer Zahl unter 50."
fi

vllt sowas?
also mit -A berücksichtig grep auch nachfolgende Zeilen.
-E für erweiterte reguläre Ausdrücke

aber ich glaube bei sowas ist awk vielleicht die bessere lösung?
Code:
if echo "$var" | awk 'BEGIN{count=0} /^[0-4][0-9]$/ {count++; if(count>=5) exit 0} {count=0} END{if(count>=5) exit 0; else exit 1}'; then
    echo "Mindestens 5 aufeinanderfolgende Zeilen haben eine Zahl unter 50."
else
    echo "Es gibt nicht genug aufeinanderfolgende Zeilen mit einer Zahl unter 50."
fi
 
  • Gefällt mir
Reaktionen: Piktogramm und GTrash81
Müsste nach [0-4] nicht ein Fragezeichen kommen?

Und wenn 09 okay ist, warum ist es dann 009 nicht?

müsste es nicht grob so sein für eine Zahl:
^0*[1-4]?[0-9]$
 
FatManStanding schrieb:
min. 5 aufeinanderfolgende Zeilen eine einstelle Zahl unter 50 haben. Ich dachte da an 'grep' in etwa sowas:
Ich habe "min. 5 aufeinanderfolgende Zeilen" für meine Lösung überlesen. ;)
Ergänzung ()

Anscheinend postest du oft irgendwas wg. Bashing.
Solltest dich damit mehr selbst beschäftigen und lernen und nicht bei jedem Problem andere für dich eine Lösung suchen lassen.
 
Zuletzt bearbeitet:
Und es schadet hier wirklich auch nicht, mal chatgpt um Hilfe zu fragen

Und btw: Bashing ist eine Fähigkeit, die man eigentlich immer brauchen kann. :p
Ich persönlich würde es eher Bash-Scripting nennen.


Das hat mir ChatGPT ausgespuckt:
Code:
#!/bin/bash

# Mehrzeilige Variable
variable='
1
2
3
4
5
100
'

# Array zum Speichern der aufeinanderfolgenden Zeilen mit Zahl < 50
lines=()

# Funktion zur Prüfung, ob 5 aufeinanderfolgende Zeilen < 50
check_consecutive() {
    count=0
    for line in "${lines[@]}"; do
        if [[ $line -lt 50 ]]; then
            ((count++))
        else
            count=0
        fi
        if ((count >= 5)); then
            echo "Mindestens 5 aufeinanderfolgende Zeilen haben eine Zahl unter 50."
            return 0
        fi
    done
    echo "Keine 5 aufeinanderfolgenden Zeilen haben eine Zahl unter 50."
    return 1
}

# Lese die Zeilen der mehrzeiligen Variable
while IFS= read -r line; do
    lines+=("$line")
    if [[ ${#lines[@]} -gt 5 ]]; then
        unset 'lines[0]'
        check_consecutive && exit 0
    fi
done <<< "$variable"

check_consecutive

Das Script ist nicht perfekt, hat aber Potential.
 
Zuletzt bearbeitet:
FatManStanding schrieb:
min. 5 aufeinanderfolgende Zeilen eine einstelle Zahl unter 50 haben. Ich dachte da an 'grep' in etwa sowas:
Ganz ohne Bash, im Dezimalsystem können einstellige Zahlen keinen Wert über 9 erreichen :)

Edit: Folgendes ist falsch! Post #12 ist besser

Code:
cat num.txt | awk 'BEGIN{i=0} $1 >= 0 && $1 <= 49 {i++; if(i>=3) {print "3er Folge gefunden"; exit 0}} {i=0} END {if(i<3) {print "nichts gefunden"}}'
Hier: "Finde am Zeilenanfang eine Zahl im Bereich 0..49, wenn dies in drei Zeilen nacheinander klappt wird Erfolg vermeldet, läuft das Programm erfolglos, wird Misserfolg ausgegeben"


PS: AWK in schön ist PITA :)
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: dms
was meinst du mit geht nicht? dein Pattern nutzt [0-4][0-9], also muss ja jede Zahl 2 Ziffern haben. Das ist in deinem Beispiel ja nicht der Fall

Das ist korrekt, hier wäre ^[0-9]$ richtig. Das Problem liegt aber denke ich beim Zeilenumbruch.

abcddcba schrieb:
Ich denke ich verstehe das Problem einfach falsch, Fakt ist aber grep -P matcht eigentlich auch Zeilenumbruch

Geht hier nicht. Wenn ich die Datei mit cat ausgebe und zu grep pipe gehen reguläre Ausdrücke:

Code:
cat aaa | grep -P ^[0-9]$

Es werden alle Zeilen mit einer Ziffer angezeigt. Sobald ich aber Zeilenumbrüche rein bringe geht das nicht mehr:

Code:
cat aaa | grep -P ^[0-9]$\n^[0-9]$

schon das geht nicht

Code:
cat aaa | grep -P ^[0-9]$\n
 
Piktogramm schrieb:
Code:
cat num.txt | awk 'BEGIN{i=0} $1 >= 0 && $1 <= 49 {i++; if(i>=3) {print "3er Folge gefunden"; exit 0}} {i=0} END {if(i<3) {print "nichts gefunden"}}'
Hier: "Finde am Zeilenanfang eine Zahl im Bereich 0..49, wenn dies in drei Zeilen nacheinander klappt wird Erfolg vermeldet, läuft das Programm erfolglos, wird Misserfolg ausgegeben"


PS: AWK in schön ist PITA :)
Ich vergebe hier den "Useless use of cat Award": https://porkmail.org/era/unix/award
 
Piktogramm schrieb:
Hier: "Finde am Zeilenanfang eine Zahl im Bereich 0..49, wenn dies in drei Zeilen nacheinander klappt wird Erfolg vermeldet, läuft das Programm erfolglos, wird Misserfolg ausgegeben"
Funktioniert nicht mit dieser Daten:
Code:
1
500
1
2
3
500
 
@tollertyp
Ist ja auch erstklassig verkackte Logik drinnen -.-

Code:
awk 'BEGIN{i=0; pre=0}
		{if ($1 >= 0 && $1 <= 49){
			if ((NR-1)==pre){
				i++; pre=NR;
				if (i>=3){ 
					exit 0;
				}
			} else {
				if (pre==0){i=1;}
			}
			pre=NR
		} else {pre=0; i=1;}
	}
END {if (!(i>=3)) {exit 1;}}' num.txt

Exitcodes sind dann in $? enthalten, oder aber noch ein && echo foo anhängen, dann wird bei $?==0 das "foo" ausgegeben.

PS: Ich mag kein AWK
 
BEGIN { cnt = 0} # Nicht zwingend
cnt >= 3 { print "found"; exit}
$1 >= 0 && $1 < 50 { cnt++; next}
{ cnt = 0 }

Man kann das auch "awk-mässig" schreiben. Dann ist das alles mögliche, aber kein PITA.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Kuristina und Piktogramm
Wofür Steht PITA? Ich kenne es nur aus dem Griechischen. Das passt, aber nicht. ;)
 
Moin,

das Thema ist schon alt, aber ich dachte ich steuere trotzdem mal eine grep-Lösung bei, wenn awk vermieden werden soll 😁

Die Testdaten:
Bash:
var1="1
2
3
4
5
100"

var2="52
36
21
700
14
8
32
44
65
7
12
04
25
33"

Die Kommandos

Wenn drei oder mehr aufeinanderfolgende Zahlen ausgegeben werden sollen:
Bash:
$ echo "$var1" | grep -Poz "(?<=^|\n)(0*[1-4]?[0-9]\n){3,}"
1
2
3
4
5
$ echo "$var2" | grep -Poz "(?<=^|\n)(0*[1-4]?[0-9]\n){3,}"
14
8
32
44
7
12
04
25
33

Wenn nur die ersten drei aufeinanderfolgenden Zahlen ausgegeben werden sollen:
Bash:
$ echo "$var1" | grep -Poz "(?<=^|\n)(0*[1-4]?[0-9]\n){3}"
1
2
3
$ echo "$var2" | grep -Poz "(?<=^|\n)(0*[1-4]?[0-9]\n){3}"
14
8
32
7
12
04

Und wenn es nur darum geht, ob drei aufeinanderfolgen, aber die Ausgabe nicht gewünscht ist:

Bash:
$ if echo "$var2" | grep -Pzq "(?<=^|\n)(0*[1-4]?[0-9]\n){3}"; then 
    echo "In der Variable sind drei aufeinanderfolgende Zahlen <= 49 enthalten"
else
    echo "In der Variable sind KEINE drei aufeinanderfolgende Zahlen <= 49 enthalten"
fi

In der Variable sind drei aufeinanderfolgende Zahlen <= 49 enthalten

Ich hoffe ihr findet die Lösung interessant - auch wenn sie spät kommt.
 
Zurück
Oben