• 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] Variable aus pipe exportieren

Graf Zahl

Newbie
Hallo zusammen,
ich kämpfe schon ein paar Tage mit folgendem Problem, nun muss ich Euch um Rat fragen:
Mein bash-script soll eine Datei durchsuchen, Zeilen mit bestimmten Wörtern herausfiltern und analysieren. Ich mache das mit folgendem script (Erklärung darunter):
Code:
COUNTER=0
grep -e "^\[Profile" "~/profile.ini" | while read t     # send lines with "[Profile" to a while loop
do
  t=${t#"[Profile"}             # cut off beginning of line
  t=${t%"]"}                    # cut off end of line (it remains a decimal number)
  if [[ $t -ge $COUNTER ]]      # if the decimal is >=$COUNTER increase $COUNTER accordingly
  then
    let "COUNTER=t+1"
    echo "in loop: "$COUNTER    # debugging info
  fi
done
echo "after loop: "$COUNTER     # debugging info
Die zu parsende Quelldatei ist "~/profile.ini", die Profile-Datei von Firefox (Pfad oben zur Veanschaulichung gekürzt):
Code:
...
[Profile0]
Name=default
IsRelative=1
Path=12345678.default
Default=1
[Profile1]
Name=test
IsRelative=1
Path=23456789.test
...
Ich suche die höchste Profilnummer in dieser Datei. Dazu interessieren mich nur die Zeilen, die [Profile*] enthalten. Die filtere ich mit grep und schicke sie als $t in die while-Schleife. Dort schneide ich [Profile und ] ab, so dass $t nur noch die Profilnummer ist. Diese vergleiche ich mit $COUNTER, um $COUNTER ggf. zu erhöhen.
Das funktioniert zunächst auch, aber $COUNTER nimmt seinen alten Wert (0) wieder an, sobald man die Schleife verlässt. Während also in der Schleife $COUNTER brav die Werte 1 und 2 annimmt (echo "in loop" ergibt 1 und 2), ist das nach der Schleife wieder vergessen (echo "after loop" ist wieder 0).
Ich habe nun schon eine ganze Weile probiert und gesucht (auch hier), aber leider keine Lösung gefunden. Könnt Ihr mir bitte helfen?
Meine Fragen:
1) Wie musss ich die Variable deklarieren, dass mir das Ergebnis $COUNTER auch nach der Schleife zur Verfügung steht?
2) (Bonusfrage ;-) WARUM ist das so? Es liegt doch bestimmt an der pipe, oder?

Vielen Dank schon vorab für Eure Hilfe!
Markus
 
Ich würde das folgend lösen
Code:
COUNTER=0

get_count()
{
	COUNTER=0
	while read tline; do
		tline=`expr "$tline" : "^\[[a-zA-Z _]*\([0-9]*\)\]$"`
		if [ "$tline" ]; then
			[ $COUNTER -lt $tline ] && COUNTER=$tline
		fi
	done < $1
}

get_count "~/profile.ini"
echo "after get_count: $COUNTER"     # debugging info

Dein Problem liegt bei grep, aber das ist sowieso ein overkill

Gruß
 

abgdf

Guru
Verarbeitung von Daten aus Dateien mit bash ist doch echt gruselig. Wo es doch z.B. für Perl so schöne Module gibt:

http://search.cpan.org/~shlomif/Config-IniFiles-2.56/lib/Config/IniFiles.pm

Gruß
 
OP
G

Graf Zahl

Newbie
Danke an Euch beide.

@ Gräfin Klara:
Als Funktion klappt es also. Das ist ja prima! Damit wäre mein Problem auch schon gelöst. Gut, dasss ich hier nicht indirekt referenzieren musste, oder so...

@abgdf:
Ich spreche leider kein Perl - deshalb hab' ich nicht allzuviel auf der Seite hinter Deinem Link verstanden. Aber z.Zt. noch egal, da ich ja dennoch weitergekommen bin - s.o.
In den Sprachen, die ich sonst spreche, muss man Dateien immer erst eine Ressource zuweisen, sie zum Lesen öffen usw. Da finde ich einen Einzeiler zum Lesen und Filtern von Dateien manchmal schon recht praktisch. Insbesondere, wenn es echt nur sowas rudimentäres ist und ich den output direkt für einen shell-Befehl brauche. Bei wilderen Sachen oder größeren Dateien nutze ich dann auch andere Methoden.

Nochmals Danke & viele Grüße,
Markus
 
Hallo Ihr,

das Problem bei dem oberen Beispiel ist eine "Besonderheit" bei bash gegenüber ksh.
a=0
cat xx | while read x
do
im loop
let a=a+1
done
echo $a

der "while...done" loop wird immer eine "Subshell" sein. Dadurch wird die Variable "a" zwar in der Subshell geändert,
das "$a" vom echo $a ist jedoch ausserhalb der Subshell.
Bei der ksh würde "while...done" nicht als Subshell laufen und dadurch würde das gewünschte Ergebnis ausgegeben.

Haveaniceday
 

abgdf

Guru
@Graf Zahl: Würd' Dir gern noch ein Beispiel in Perl zeigen, aber dazu müßtest Du das Modul installieren, und die vielen Sonderzeichen von Perl würden Dich wahrscheinlich verwirren.
Daher hier mal ein Beispiel in Python (meiner Lieblingssprache, die die meisten Module (wie "ConfigParser") gleich mitbringt):
Code:
#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-

import os
import sys
import ConfigParser

# os.getenv("HOME") entspricht dem ~-Verzeichnis:
fname = os.path.join(os.getenv("HOME"), "profile.ini")

if not os.path.isfile(fname):
    print "File '" + fname +"' not found."
    sys.exit(1)

cp = ConfigParser.ConfigParser()
cp.read(fname)

x = 0

for i in cp.sections():
    if i.startswith("Profile") and i != "Profile":
        nr = i.split("Profile")[1]
        if nr.isdigit():
            nr = int(nr)
            if x < nr:
                x = nr
        else:
            print "Warning: Section '" + i + "' contains something after 'Profile', that's not a number!"
            continue

print x
Gruß
 
OP
G

Graf Zahl

Newbie
@ haveaniceday,
ich meine, das würde auch in der bash funktionieren. Deswegen läuft ja Gräfin Klaras code. Aber auch ausserhalb einer Funktion habe ich das in einem bash-script getestet:

COUNTER=0
while read t; do
# mach irgendwas
COUNTER=1
done < infile.txt

Hier ist COUNTER nach der Schleife gleich 1. Mit einer Pipe hingegen:

cat infile.txt | while read t; do
# mach irgendwas
echo $t
COUNTER=1
done

ist COUNTER nach der Schleife gleich 0. Während ein redirect klappt, ist bei einer pipe also Ende. Da habe ich wieder was gelernt.
___
@abgdf
Danke für den code! Soo verwirrend ist das eigentlich nicht, hat ja was von c. Und wie schon erwähnnt nutze ich bei Bedarf auch Programmimersprachen, um komplexere Probleme zu lösen - nur eben kein Perl. Aber das kann ja noch kommen, die Neugierde ist nun geweckt... ;-)

Viele Grüße
 
Etwas spät, aber ich hab ihn noch gefunden: Einen Link mit ein paar Besonderheiten und
Unterschieden in den Shells:
ftp://ftp.cwru.edu/pub/bash/FAQ

"E4" Behandelt dabei das Thema von diesem Thread.

Haveaniceday
 
Oben