String und Integer in der bash

  • Ich habe mein Problem hier schon ausführlich dargestellt und auch schon fast gelöst, aber ich habe eine grundsätzliche Frage an euch Scriptexperten.


    Mit

    Bash
    #!/bin/bash
    secs="$(svdrpsend.pl NEXT rel | egrep "^250" | cut -d' ' -f3)"

    erhalte ich die Zeit in Sekunden bis zum nächsten Timer. Diese 'Zahl' ist negativ, falls ein Timer gerade aktiv ist. Dummerweise ist die Ausgabe von svdrpsend.pl aber ein String und somit ist '$secs' auch ein String und nicht vom Typ Integer. Jeglicher Versuch mit

    Code
    if [ "$secs" -gt 0 ]; then
    oder
    if [ "$secs" < 0 ]; then

    evaluieren entweder in beiden Fällen ('-gt' und '-lt' bzw. '<' und '>') zu '0' (!) oder zu einer Fehlermeldung (bin nicht zu Hause und kann sie daher nicht genau wiedergeben).


    Fein. Wenn ich '$secs' an ein Perl Script übergebe, dann kann ich dort alle möglichen Rechenoperationen ausführen.


    /usr/local/bin/test.pl (bitte nicht hauen falls die Syntax nicht ok ist. Ich habe eigentlich Null Ahnung von Perl):

    Code
    $zahl = ARGV[0]
    chomp $zahl;
    @a=$zahl  # nicht über die Zuwesiung wundern. Ich habe das an einen Beispielcode angepasst
    print eval(a[0] * -1,"\n");

    Dieses Perl Script kann ich natürlich wunderbar von der bash aus aufrufen, aber warum funktioniert das in der bash selbst nicht (das Rechnen meine ich. Ich weiss, dass ich einige Dinge dort anders schreiben müsste)?


    Ich würde mir jetzt so helfen, daß ich die if-Abfragen in dem Perl Script ausführe und dann einen Wert an die bash zurückgebe, den ich dort auswerten kann

    Code
    ergebnis="$(/usr/bin/perl /usr/local/bin/test.pl $secs)";
    if [ "$ergebnis" == "Dies"); then tue_dies
    else
      if [ "$ergebnis" == "Jenes"); then tue_jenes
      fi
    fi

    Auch ein

    Bash
    #!/bin/bash
    declare -i secs

    hat nichts an dem Verhalten in der bash geändert.


    Vielleicht mache ich mich mit der Frage ja komplett lächerlich, aber bevor ich mit meinem VDR angefangen habe (Datum steht in der Signatur) hatte ich Null Ahnung von Linux. Ich würde mich über eine Erklärung freuen.


    Gruß,
    Marcus

    Mein VDR built 21.07.04 15:29
    VDR 1.3.24enAIO2.2, DVB-CVS, FW261e (Plugins: dvd-cvs,epgsearch,femon,graphTFT,osd-teletext,text2skin-cvs,vcd,vdrcd,vdrconvert 0.2.0,mplayer) unter Suse 9.3
    Asus P4P800VM, P4 2.8Ghz, 512 MB in ATC-620C-BX1
    2x Maxtor 5A300J0, SD-M1802, 7" TFT (Pollin)
    TT DVB-C 2.1 (4MB SDRAM), SL DVB-T

  • Zitat

    Original von marcmerz
    [...] Jeglicher Versuch mit

    Code
    if [ "$secs" -gt 0 ]; then
    oder
    if [ "$secs" < 0 ]; then

    evaluieren entweder in beiden Fällen ('-gt' und '-lt' bzw. '<' und '>') zu '0' (!) oder zu einer Fehlermeldung (bin nicht zu Hause und kann sie daher nicht genau wiedergeben).
    [...]

    Lass einfach die Quotes weg, dann wird's schon gehen:

    Code
    if [ $secs -gt 0 ]; then
    oder
    if [ $secs < 0 ]; then

    Godzilla [Low Budget Record-Only]: AMD K6/2(400), Gigabyte GA-5AX, 192MB, ATI RagePro (Mach64GT) mit TV-Out, Technisat Skystar2 rev 2.6b, IBM DTLA 40GB, Ensoniq ESS-Solo1 (es1935), Pioneer DVR 108

  • Hi metahawk,

    Zitat

    Original von metahawk
    [...]
    Lass einfach die Quotes weg, dann wird's schon gehen:

    Code
    if [ $secs -gt 0 ]; then
    oder
    if [ $secs < 0 ]; then


    Ich bin mir ziemlich sicher, daß ich alle möglichen Kombinationen von Schreibweisen in der if-Abfrage ausprobiert habe (ohne den gewünschten Erfolg zu erzielen), aber ich probiere das heute Abend gerne nochmal mit Deiner Schreibweise aus. Ich bekam unter anderem auch die Fehlermeldung '...:integer expression expected' bzw. 'unary expression expected', aber ich weiss nicht mehr genau in welchem Zusammenhang. Danke für den Hinweis.


    Gruß,
    Marcus

    Mein VDR built 21.07.04 15:29
    VDR 1.3.24enAIO2.2, DVB-CVS, FW261e (Plugins: dvd-cvs,epgsearch,femon,graphTFT,osd-teletext,text2skin-cvs,vcd,vdrcd,vdrconvert 0.2.0,mplayer) unter Suse 9.3
    Asus P4P800VM, P4 2.8Ghz, 512 MB in ATC-620C-BX1
    2x Maxtor 5A300J0, SD-M1802, 7" TFT (Pollin)
    TT DVB-C 2.1 (4MB SDRAM), SL DVB-T

    Einmal editiert, zuletzt von marcmerz ()

  • Servus,


    das ist ein Problem mit der Variablen-Ersetzung, über das du hier gestolpert bist.


    Zitat

    Lass einfach die Quotes weg, dann wird's schon gehen:


    Nein, das geht genauso wenig.


    Workaround:

    Code
    if [ ${secs:0:1} = "-" ]; then
      echo negativ
    fi

    Eine andere Möglichkeit ist "eval", aber auch ziemlich unschön:

    Code
    if [ $(eval echo ${secs}) -gt "0" ]; then
      echo positiv
    else
      echo negativ
    fi

    Ich würde hier die erste Möglichkeit wählen.


    Viele Grüße, Mirko

  • Hi Mirko,


    Ich war mir auch ziemlich sicher, daß das weglassen der "" nichts ändert (ich habe Stunden davor gesessen :rolleyes: ) aber ich hätte es heute Abend nochmal ausproberit.


    Wenn ich Deinen Code richtig verstehe, prüfst Du in

    Code
    if [ ${secs:0:1} = "-" ]; then

    ob das erste Zeichen ein '-' ist. Ich habe das gleiche schon mit

    Code
    timer="$(svdrpsend.pl NEXT rel | egrep "^250" | cut -d' ' -f3 | cut -c1)"

    gemacht. Ich möchte aber nicht nur wissen ob ein Timer aktiv ist (das war 1.te Priorität), sondern auch die Möglichkeit haben zu wissen, wann der nächste Timer anfängt. Grund: Wenn es nur noch 180 Sekunden bis zum nächsten Timer sind, möchte ich das Script (das später als cronjob läuft) nicht ausführen lassen. Dafür muss ich aber in der Shell (oder auch in Perl wenn es nicht in der Shell geht) rechnen können. Ich werde den Weg über 'eval' probieren. Mittlerweile bin ich auch über Rechnen in UNIX-Shell-Prozeduren gestolpert (-> expr). Mal sehen...


    BTW: Hast Du einen Link wo ich über die 'Problematik der Variablen-Ersetzung' was nachlesen kann?


    Danke für die Tipps.


    Gruß,
    Marcus

    Mein VDR built 21.07.04 15:29
    VDR 1.3.24enAIO2.2, DVB-CVS, FW261e (Plugins: dvd-cvs,epgsearch,femon,graphTFT,osd-teletext,text2skin-cvs,vcd,vdrcd,vdrconvert 0.2.0,mplayer) unter Suse 9.3
    Asus P4P800VM, P4 2.8Ghz, 512 MB in ATC-620C-BX1
    2x Maxtor 5A300J0, SD-M1802, 7" TFT (Pollin)
    TT DVB-C 2.1 (4MB SDRAM), SL DVB-T

  • Schau Dir mal den Inhalt von $secs genauer an:


    Code
    greywolf@helium:~$ secs=$(svdrpsend.pl next rel | grep "^250" | cut -d' ' -f3)
    greywolf@helium:~$ echo -n "$secs" | hexdump -C    
    00000000  2d 31 31 31 0d                                    |-111.|
    00000005


    svdrpsend beendet Zeilen also mit <cr><lf> (Carriage Return [=0x0d] + Linefeed [=0x0a]). Das <lf> wird von der bash automatisch entfernt (Zeilenende), aber das <cr> bleibt übrig und sorgt dafür, dass der String nicht als Zahl interpretiert werden kann ...


    Lösung:

    Code
    secs="$(svdrpsend.pl NEXT rel | egrep "^250" | cut -d' ' -f3 | tr -d '\r')"


    entfernt das <cr> und ermöglicht so einen numerischen Vergleich.

  • Greywolf
    Nee, oder?!


    Fein...noch mehr gelernt. Warum das dem Perl Interpreter egal ist, frage ich jetzt nicht. ?(


    Vielen Dank dafür. Dann kann ich ja in der bash bleiben und muss nicht den Umweg über Perl gehen. Und bei dem nächsten Problem dieser Art, schaue ich sofort in den Hexdump (PostingausdruckundandieWandnagel)


    Schönes Wochenende
    Marcus

    Mein VDR built 21.07.04 15:29
    VDR 1.3.24enAIO2.2, DVB-CVS, FW261e (Plugins: dvd-cvs,epgsearch,femon,graphTFT,osd-teletext,text2skin-cvs,vcd,vdrcd,vdrconvert 0.2.0,mplayer) unter Suse 9.3
    Asus P4P800VM, P4 2.8Ghz, 512 MB in ATC-620C-BX1
    2x Maxtor 5A300J0, SD-M1802, 7" TFT (Pollin)
    TT DVB-C 2.1 (4MB SDRAM), SL DVB-T

  • Servus,


    Zitat

    entfernt das <cr> und ermöglicht so einen numerischen Vergleich.


    Hast du das wirklich bis zu Ende ausprobiert? Mit dem numerischen Vergleich? Kann ich mir kaum vorstellen.


    Die Bash mag das Minus am Anfang der Variablen auch dann nicht, wenn du die Zahl von Hand setzt, z.B. mit secs="-5288"


    marcmerz:
    Das war doch nur ein Beispiel, wie du die negativen Zahlen aussiebst!


    Wenn die Zahl positiv ist, kannst du anschließend normal weiter rechnen, weil du keine Probleme mit dem Vorzeichen hast. Mit Minus weißt du gleich von vornherein, dass du nicht weiter machen brauchst (weil ein Timer läuft).


    Viele Grüße, Mirko

  • Zitat

    Original von cooper


    Hast du das wirklich bis zu Ende ausprobiert? Mit dem numerischen Vergleich? Kann ich mir kaum vorstellen.


    Doch, natürlich. 8)


    Code
    greywolf@matrix:~$ TEST="-1"
    greywolf@matrix:~$ test "$TEST" -lt 0 && echo "TEST<0" || echo "TEST>=0 oder Fehler"
    TEST<0
    greywolf@matrix:~$ TEST="1"
    greywolf@matrix:~$ test "$TEST" -lt 0 && echo "TEST<0" || echo "TEST>=0 oder Fehler"
    TEST>=0 oder Fehler
    greywolf@matrix:~$ bash --version
    GNU bash, version 3.00.15(2)-release (i486-slackware-linux-gnu)
    Copyright (C) 2004 Free Software Foundation, Inc.


    Auch ohne Anführungszeichen funktioniert es hier übrigens. Es gibt nur unterschiedliche Fehlermeldungen, falls man einen Leerstring in der Variablen hat:


    Code
    greywolf@matrix:~$ TEST=""
    greywolf@matrix:~$ test $TEST -lt 0 && echo "TEST<0" || echo "TEST>=0 oder Fehler"
    bash: test: -lt: unary operator expected
    TEST>=0 oder Fehler
    greywolf@matrix:~$ test "$TEST" -lt 0 && echo "TEST<0" || echo "TEST>=0 oder Fehler"
    bash: test: : integer expression expected
    TEST>=0 oder Fehler


    Zitat

    Die Bash mag das Minus am Anfang der Variablen auch dann nicht, wenn du die Zahl von Hand setzt, z.B. mit secs="-5288"


    ?( Weder mit der 3er (s.o.) noch mit einer 2.05b bash kann ich da irgendwelche Probleme mit negativen Zahlen feststellen.

  • Hi cooper,


    im Moment benutze ich

    Code
    TIMER="$(svdrpsend.pl NEXT rel | egrep "^250" | cut -d' ' -f3 | tr -d '\r')";
    
    
    if [ "$TIMER" -gt 180 ]; then

    und das funktioniert (getestet mit negativen und positiven Werten).

    Code
    # bash --version
    GNU bash, version 2.05b.0(1)-release (i586-suse-linux)
    Copyright (C) 2002 Free Software Foundation, Inc.


    Ich meinte auch nur verstanden zu haben, daß Dein Code auf das erste Zeichen in der Zeichenkette testet. Der Ansatz von Dir ist nicht schlecht. Im Moment funktioniert obiger Test von Greywolf ohne weitere Eingriffe.


    Gruß,
    Marcus


    P.S.: Ich werde mir trotzdem mal eval und expr anschauen.

    Mein VDR built 21.07.04 15:29
    VDR 1.3.24enAIO2.2, DVB-CVS, FW261e (Plugins: dvd-cvs,epgsearch,femon,graphTFT,osd-teletext,text2skin-cvs,vcd,vdrcd,vdrconvert 0.2.0,mplayer) unter Suse 9.3
    Asus P4P800VM, P4 2.8Ghz, 512 MB in ATC-620C-BX1
    2x Maxtor 5A300J0, SD-M1802, 7" TFT (Pollin)
    TT DVB-C 2.1 (4MB SDRAM), SL DVB-T

    2 Mal editiert, zuletzt von marcmerz ()

  • Zitat

    ?( Weder mit der 3er (s.o.) noch mit einer 2.05b bash kann ich da irgendwelche Probleme mit negativen Zahlen feststellen.


    Ich leider schon, evtl. liegt es auch daran, dass du "test" benutzt und nicht das Builtin der Bash. "test" ist ein externer Aufruf.


    Viele Grüße, Mirko

  • Zitat

    Original von cooper


    Ich leider schon, evtl. liegt es auch daran, dass du "test" benutzt und nicht das Builtin der Bash. "test" ist ein externer Aufruf.


    Ohne Pfadangabe nicht:


    Code
    greywolf@matrix:~$ type test
    test is a shell builtin
    greywolf@matrix:~$ man bash
    [..]
    CONDITIONAL EXPRESSIONS
           Conditional expressions are used by the [[  compound  com-
           mand  and  the  test  and  [ builtin commands to test file
           attributes and perform string and arithmetic  comparisons.
    [..]


    Also nochmal alle möglichen Varianten ausprobiert:


    Code
    greywolf@matrix:~$ TEST=-1
    greywolf@matrix:~$ echo $TEST
    -1
    greywolf@matrix:~$ test $TEST -lt 0 && echo ok
    ok
    greywolf@matrix:~$ /usr/bin/test $TEST -lt 0 && echo ok
    ok
    greywolf@matrix:~$ [[ $TEST -lt 0 ]] && echo ok
    ok


    Selbst wenn im ersten Fall doch das externe test benutzt werden sollte, "[[" ist definitiv bash built-in und funktioniert (hier ...). Seltsam ... ?(

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!