• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

[gelöst] grep-Zeilen auswerten?

Treito

Hacker
Hallo,

der Befehl
Code:
grep -C1 -l 'inside an USB' /sys/class/input/input*/name |gawk -F/name '{ print $1 }'
spuckt bei mir die beiden Zeilen
Code:
/sys/class/input/input3
/sys/class/input/input4
aus. Kann ich jeweils eine Zeile einer Variablen zuweisen? Oder kann ich erreichen, dass der o.g. Befehl nach der ersten Zeile stoppt?

Gruß,

Sven
 

marce

Guru
Möglichkeiten gibt's viele, am schnellsten fällt mir ein:

- pipe in head
- Ausgabe an Array übergeben
- ...
 
OP
T

Treito

Hacker
okay danke, das scheint zu funktionieren und wie könnte ich nur die 2. Zeile ausgeben lassen?
 
OP
T

Treito

Hacker
ah danke, jetzt kapiere ich, was dieser tail-Befehl bewirkt...
tail -f /var/log/messages kannte ich...
 
A

Anonymous

Gast
Treito schrieb:
okay danke, das scheint zu funktionieren und wie könnte ich nur die 2. Zeile ausgeben lassen?
ganz einfach, die ersten 2 Zeilen auswählen und davon die letzte.
Code:
grep -C1 -l 'inside an USB' /sys/class/input/input*/name |gawk -F/name '{ print $1 }' | head -2 | tail -1
usw. Das hat aber eine Sackgasse, stell dir mal vor da gibt es nur 3 Ausgaben und du sucht dennoch die 4. 5. und 6. Zeile aus. Die haben dann immer den Inhalt der letzten.

Also ist dieses Konzept nicht so richtig zu gebrauchen, da es keine Ablaufsteuerung hat, die abbricht wenn keine Zeilen mehr da sind.
besser das ganze dann in einer while-Schleife laufen zu lassen, die bricht dann schon ab wenn es nichts mehr gibt.

Code:
typeset -i i=1
while read INHALT $(grep -C1 -l 'inside an USB' /sys/class/input/input*/name |gawk -F/name '{ print $1 }' )
do
  echo " $i Zeile   -> "$INHALT"
  i=$i+1
# hier könnten jetzt deine Befehl stehen.
done

oder das Ganze in eine Variable schreiben und dann diese dann mit einer while-Schleife auslesen und verarbeiten.
Code:
ALLES=$(grep -C1 -l 'inside an USB' /sys/class/input/input*/name |gawk -F/name '{ print $1 }' )
echo "$ALLES" | while read INHALT; do echo "$INHALT"; done

Was mich an der ganzen Geschichte stört die Verwendung von grep + awk das ist wie Fahradschieben anstatt sich draufzusetzen und damit zu fahren. ;) Awk ist viel mächtiger und das bischen grep macht es nebenbei.
Code:
awk '/inside an USB/ {split(FILENAME,a,/\/name/) ; print a[1] ; nextfile}' /sys/class/input/input*/name
(hoffe das funktioniert so, ich kann es nicht direkt testen, da ich die entsprechenden Dateien nicht haben)
gefällt mir da bedeutend besser, auch wenn es hier nicht kürzer wird in der Schreibweise, bei entsprechend vielen Files müsste man mal testen ob es so wenigsten schneller ist. Für den Laien sind sowieso beide Zeilen unverständlich. ;)

robi
 
OP
T

Treito

Hacker
Ich glaube, ich muss mich mal mit der Shell-Programmierung auseinandersetzen...

Ich hatte diesen grep-Befehl in Zusammenhang mit einer sed-pipe gefunden, aber da störte mich das /name am Ende. In der für mich nur Bahnhof-man-Page bzw. der Info-Page war ein Verweis auf awk und ein wenig googlen brachte mich auf die Pipe. Ich hatte noch im Hinterkopf, dass man mit awk Strings kürzen kann.

Hintergrund bei der ganzen Geschichte ist, dass ich 2 DVB-USB-Sticks habe mit jeweils einem IR-Receiver und ich ermitteln wollte, welche /dev/input/eventX denen zugewiesen wurde. Mal ist es 4+6, dann 7+8, dann 5+6. Damit kann man doch nicht arbeiten, aber ich habe mittlerweile wohl eine andere Lösung gefunden, wobei ich der noch nicht ganz traue.
 

abgdf

Guru
robi schrieb:
Das hat aber eine Sackgasse, stell dir mal vor da gibt es nur 3 Ausgaben und du sucht dennoch die 4. 5. und 6. Zeile aus. Die haben dann immer den Inhalt der letzten.
Allgemein gezielt eine bestimmte Zeile ausgeben zu lassen, wäre mit folgendem kleinen Perl-Skript "prline.pl" auch kein großes Problem:
Code:
#!/usr/bin/perl

use warnings;
use strict;

# prline.pl

my @lines = <stdin>;

if ($#lines < 0 || $#ARGV < 0 || $ARGV[0] =~ /\D/ || $ARGV[0] == 0) {
    print "Usage: echo \"sometext\" | prline.pl 1\n";
    exit(1);
}

if ($ARGV[0] - 1 > $#lines) {
    print "Error: Line-number out of range.\n";
    exit(2);
}

print $lines[$ARGV[0] - 1];
Wie gesagt zu benutzen:
Code:
echo "sometext" | prline.pl 1
usw.

Gruß
 

framp

Moderator
Teammitglied
robi schrieb:
... Awk ist viel mächtiger und das bischen grep macht es nebenbei.
Code:
awk '/inside an USB/ {split(FILENAME,a,/\/name/) ; print a[1] ; nextfile}' /sys/class/input/input*/name
Funktioniert prächtig!

Noch eine Variante für die Freunde von perl :roll:
Code:
perl -n -e 'if (/inside an USB/) { print "$ARGV[0]\n";}' /sys/class/input/input*/name
 
Hmm, reicht da nich ein kleiner sed-Einzeiler ?
(ungetestet)
Code:
sed -n '/inside an USB/!d;s#/name.*$##;p;q' /sys/class/input/input*/name
Und z.B. nur 3.+5 Zeile ausgeben:
Code:
sed -n '/inside an USB/!d;s#/name.*$##;p' /sys/class/input/input*/name | sed -n '3p;5p'

Haveaniceday

PS: Erklärung:
-n => keine default Ausgabe
/inside an USB/!d => alles was diesen Text nicht enthält löschen...
s#/name.*$## => /name.* abschneiden
p => alles was hier ankommt wollen wir ausgeben...
q => Eins reicht uns.
 
A

Anonymous

Gast
haveaniceday schrieb:
Hmm, reicht da nich ein kleiner sed-Einzeiler ?
sed ist hier gar keine gute Idee, schau dir noch mal genau das grep im ersten Beitrag an. Das entscheidende ist die Option "-l" . Es wird zwar in der Datei gesucht, aber der Dateiname wird dann ausgegeben. Dazu fällt mir bei sed nichts passendes ein.

robi
 
OP
T

Treito

Hacker
Nein bei dem sed-Einzeiler kommt dann auch folgendes heraus:
IR-receiver inside an USB DVB receiver

So nun ist es fertig, witzigerweise brauche ich jetzt das awk nun doch nicht mehr. Ist allerdings erst einmal nur ein Testscript, ich habe gesehen, das SuSE doch etwas anders arbeitet.

Code:
#!/bin/bash
lircinputdev=`grep -l 'inside an USB' /sys/class/input/input*/name |head -n 1`
echo $lircinputdev
[ -z "$lircinputdev" ] || lirceventdev=`dirname "$lircinputdev" | sed -e's+/sys/class/input/input+/dev/input/event+'`
echo "-H dev/input -d $lirceventdev"

Ich hatte ein Goßteil des Scriptes aus einem Blog...

http://www.mythdora.com/?q=node/2066
 

framp

Moderator
Teammitglied
Treito schrieb:
Nein der perl-Befehl geht nicht, er eleminiert das /name am Ende nicht.
Das habe ich übersehen :eek:ps:
Code:
perl -n -e 'if (/inside an USB/) { $ARGV[0]=~/(.*)\/.*$/; print "$1\n";}' /sys/class/input/input*/name
 
Oben