Hinweis: Das Forum wird geschlossen! Neue Registrierungen sind nicht mehr möglich!

 Zurück zu Pro-Linux   Foren-Übersicht   FAQ     Suchen    Mitgliederliste
in BASH for schleife mit 2 laufvariablen

 
Neuen Beitrag schreiben   Auf Beitrag antworten    Pro-Linux Foren-Übersicht -> Programmieren - Allgemein
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
killerhippy



Anmeldungsdatum: 19.05.2000
Beiträge: 529

BeitragVerfasst am: 13. Dez 2002 18:22   Titel: in BASH for schleife mit 2 laufvariablen

Hi Bashscripter,

mir geht's darum, in einer Variable mehrere zusammengehörige Paare als doubles in einer for schleife zu verwenden.
Das advanced Bash-scripting Howto liefert ein prima Beispiel, das auch genauso funktioniert, wie ich es verwenden möchte.

allerdings möchte ich die Paare in einer Variable im Kopf des Listings definieren, damit man es easy editieren kann und neue Paar editieren kann, ohne die for schleife finden zu müssen.

code:

Wie definiert man planets im Kopf des listings, sodass set $x trotzdem richtig expandiert wird?
Meine Versuche schlugen fehl.
Soll also in etwa so ausssehen:

#!/bin/bash
# Planets revisited.
planets='"Mercury 36" "Venus 67" "Earth 93" "Mars 142" "Jupiter 483"'
...
for x in $planets; do
set $x
echo "$1 $2,000,000 miles from the sun"
...

wie macht man's?

---schnipp---
Example 3-27. for loop with two parameters in each [list] element

#!/bin/bash
# Planets revisited.

# Want to associate name of each planet with its distance from the sun.

for planet in "Mercury 36" "Venus 67" "Earth 93" "Mars 142" "Jupiter 483"
do
set $planet # Parses variable "planet" and sets positional parameters.
# May need to save original positional parameters, since they get overwritten.
echo "$1 $2,000,000 miles from the sun"
#-------two tabs---concatenate zeroes onto parameter $2
done

exit 0
---schnapp---


_________________
Es gibt keine dumme Fragen!

Killerhippy


Zuletzt bearbeitet von killerhippy am 13. Dez 2002 18:22, insgesamt 3-mal bearbeitet
 
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen

rattengift
Gast





BeitragVerfasst am: 13. Dez 2002 21:42   Titel: Re: in BASH for schleife mit 2 laufvariablen

code:

IFS=","
planet="Mercury 36,Venus 67,Earth 93,Mars 142,Jupiter 483"
for object in $planet
do
IFS=" "
set $object
echo "$1 $2,000,000 miles from the sun"
done
exit 0

ps: IFS ist der internal field separator. nicht sehr schön, aber so tuts. ich würd ja eher 2 arrays verwenden (einen für den namen und einer für die distanz, der code wäre sauberer).
 

killerhippy



Anmeldungsdatum: 19.05.2000
Beiträge: 529

BeitragVerfasst am: 14. Dez 2002 15:54   Titel: Re: in BASH for schleife mit 2 laufvariablen

Hi rattengift,

vielen Dank für den Tip, das ist genau das, was ich brauche.

...wie stellste dir das in zwei arrays vor? AFAIK bzw. zwei schleifen systeme kenne, wird der äußeren laufvariable jede innere laufvariable gegengehalten. oder wie geht das ohne for schleife?

übrigens ist die paarweise einrichtigung in der variable im scriptkopf sinniger, weil ich an einem iptables-script bastele und da soll das dann so aussehen:

SERVICES="pop-3 <ip-pophost>, smtp <ip-smtphost>, ftp, http, ssh <ip-trustedhost>"

und das funzt mit der IFS variable super.
_________________
Es gibt keine dumme Fragen!

Killerhippy
 
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen

rattengift
Gast





BeitragVerfasst am: 14. Dez 2002 18:02   Titel: Re: in BASH for schleife mit 2 laufvariablen

> ...wie stellste dir das in zwei arrays vor?

hm, mit IFS ist vielleicht doch besser als mit arrays, man kann es auch noch etwas übersichtlicher machen; du kannst übrigens auch mehrere trennzeichen zulassen (siehe code).
mit arrays spart man sich zwar das IFS-gefummle, braucht aber eine zählervariable. das lohnt sich, wenn man nicht nur die ganze liste abarbeiten, sondern auch mal über die position direkt auf ein bestimmtes element zugreifen will (je nachdem ob du das brauchst).
code:
variante mit IFS

#!/bin/bash

IFS="," # trenne bei ","
SERVICES="pop-3 (ip-pophost), smtp (ip-smtphost), ssh (ip-trustedhost)"

for object in $SERVICES
do
IFS=" ()" # trenne bei " ", "(" und ")"
set $object
echo "$1: $2"
done
#IFS=" "
exit 0


mit arrays:


#!/bin/sh
SERVICE=(pop-3 smtp ssh)
SERV_IP=(ip1 ip2 ip3)

c=0
while [ "${SERVICE[c]}" != "" ]; do
printf "${SERVICE[c]}: ${SERV_IP[c]}\n"
c=$[ c + 1 ]
done

exit 0

ob das so nun besser ist, hängt natürlich von deiner anwendung ab.
 

Jochen
Gast





BeitragVerfasst am: 14. Dez 2002 18:39   Titel: Re: in BASH for schleife mit 2 laufvariablen

Kleiner Gag am Rande, rattengift: Deine erste Variante würde so auch in der alten Bourne-Shell laufen. also dürfte die erste Zeile des Skripts auch "#!/bin/sh" lauten. Deine zweite Variante nutzt Arrays, die die alte Bourne-Shell nicht kennt. Daher sollte hier "#!/bin/bash" stehen...

IFS zu ändern ist nicht ganz ohne, da IFS an einigen Stellen von der Shell verwendet wird, u.a. beim Zerlegen der Skript-Zeilen selbst. Wenn man es nicht in einem sehr kleinen, überschaubaren Skript macht, würde ich aus Vorsicht immer so vorgehen:
code:

OLD_IFS="$IFS"
IFS="mein-neues-trennzeichen"
# Mache etwas, wozu IFS geändert sein muss
IFS="$OIFS"



Und zu den Arrays muss man nicht unbedingt händisch eine Zählervariable mitführen, wenn man ein bisschen tricksen kann: Man verwende die Arrays auf 1 basiert, d.h. mit 1 als kleinstem Index, und lückenfrei:
declare -a ARR=([1]=eins zwei drei)
Dann kann man mittels seq eine for-schleife über alle Elemente basteln:
for I in $(seq 1 ${#ARR[*]}) ; do echo $I ${ARR[$I]} ; done
Das zweite Argument zu seq ergibt die Anzahl der Elemente in einem Array.

Die Schreibweise ist vielleicht nicht sehr eingänglich, aber man kannn nicht mehr vergessen, den Schleifenzähler hochzuzählen...

Jochen
 

killerhippy



Anmeldungsdatum: 19.05.2000
Beiträge: 529

BeitragVerfasst am: 14. Dez 2002 19:38   Titel: Re: in BASH for schleife mit 2 laufvariablen

@rattengift:

mein <ip-soundso> geraffel sollte nur ein Platzhalter für eine echte IP sein. :)

aber trotzdem danke, das kann ja für andere scripte von Nutzen sein!

@Jochen:

vor lauter mp3 hören und bier saufen (immerhin ist ja wochenende) kann ich z.Z. deine Intelligenz nicht nachvollziehen, zumal ich eigentlich DOD spiele inzwischen...

aber morgen, so UltraBord-v1.6.1 will, kann ich ja morgen mit kater noch mal nachlesen...

thanx-so-much
_________________
Es gibt keine dumme Fragen!

Killerhippy
 
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen

rattengift
Gast





BeitragVerfasst am: 14. Dez 2002 20:50   Titel: Re: in BASH for schleife mit 2 laufvariablen

Hi Jochen,

> Daher sollte hier "#!/bin/bash" stehen...

richtig. ich schreib aus alter gewohnheit eben "sh", und weil das zeug bei mir sowieso unter der bash läuft, hab ich noch gar nicht gemerkt, dass das in manchen fällen nicht gut ist. übrigens: ein macosX-user erzählte mir, dass man in osX die shellscripts einfach mit "#!sh" einleitet. eigentlich einleuchtend, sh ist ja sowieso im pfad, und falls es dann doch mal nicht in /bin liegen sollte, ist man auf der sicheren seite.

> OLD_IFS="$IFS"; ...; IFS="$OIFS"

ACK. ich hatte es ursprünglich drin, dachte dann aber: warum so ein kleines script unnötig aufblähen?! aber du hast schon recht: besser ein backup machen.

> declare -a ARR=([1]=eins zwei drei)

raffiniert. allerdings handelt man sich mit dem "seq" eine äussere abhängigkeit (portabilität!) ein, anstatt auf bash-builtins zu vertrauen. der code wird auch nicht unbedingt lesbarer (jemand, der zb nur pascal kennt, wird die while-schleife ohne probleme verstehen, das seq muss er erst mal nach-man'en). vor allem aber bringe ich es als alter C-(usw)-programmierer nicht übers herz, einen array bei irgendetwas anderem als 0 beginnen zu lassen!
also ich würde die alte, ehrliche while-schleife mit laufvariable vorziehen. oder als kompromiss:
code:
declare -a SERVICE=(pop-3 smtp ssh) # 0..(n-1), wie es sich gehört
declare -a SERV_IP=(ip1 ip2 ip3) #
for I in $(seq 1 ${#SERVICE[*]}); do printf "${SERVICE[I-1]}: ${SERV_IP[I-1]}\n"; done

frage: dem array-index hast du "$" vorangestellt: ARR[$I]. ich dachte erst, es sei falsch, hab dann aber gemerkt, dass *beides* geht. gibt es dafür eine erklärung? (normalerweise ist man ja froh, wenn es *überhaupt* geht, und hier geht nun beides?? kopfschüttel...).

> Das zweite Argument zu seq ergibt die Anzahl der Elemente in einem Array.

hm, ich habe in man bash sowas gesucht, es aber wohl übersehen. das kann man in die while-bedingung einbauen anstatt dort (unschön) die array-elemente abzufragen.
while [ $c -lt ${#SERVICE[*]} ]; do

@sascha

> mein <ip-soundso> geraffel sollte nur ein Platzhalter für eine echte IP sein.

schon klar, aber wieso, was hab ich denn damit angestellt?
 

Jochen
Gast





BeitragVerfasst am: 15. Dez 2002 18:56   Titel: Re: in BASH for schleife mit 2 laufvariablen

> allerdings handelt man sich mit dem "seq" eine äussere abhängigkeit (portabilität!) ein,

Das ist sicherlich richtig. Ist aber alles Ansichtssache: Ein für unsere Zwecke ausreichendes Minimal-seq ist mit bash-Mitteln schnell erstellt:
code:

function loop { # Jetzt mal loop benannt, damit es sich nicht mit seq beisst
case $# in
1) START=1; END=$1 ; DIS=1 ;;
2) START=$1; END=$2 ; DIS=1 ;;
3) START=$1; END=$2 ; DIS=$3 ;;
*) echo "Usage: $0 endvalue|startvalue endvalue [displacement]" >&2; exit 1;;
esac

while (( START <= END )) ; do
echo $START
(( START += DIS ))
done
}

Man sollte jetzt auch die Parameter prüfen usw., aber für's erste reicht. Allerdings gebe ich Dir gerne recht, dass bei der Array-Deklaration die Leserlichkeit nicht wirklich gut ist und dass auch bei mir ein 1-basiertes Array ein gewisses Unwohlsein hervorruft. Eigentlich habe ich es nur genommen, um nicht
for I in $( seq 1 (( ${#ARR[*]} - 1 )) ) ; do echo $I ${ARR[$I]} ; done
schreiben zu müssen. Damit ist der Endwert einmal im Schleifenkopf berechnet. Ansonsten muss bei jedem Schleifendurchlauf der Index um 1 angepasst werden - viel zu viel Aufwand...

> frage: dem array-index hast du "$" vorangestellt: ARR[$I]. ich dachte erst, es sei falsch, hab dann aber gemerkt,
> dass *beides* geht. gibt es dafür eine erklärung? (normalerweise ist man ja froh, wenn es *überhaupt* geht,
> und hier geht nun beides?? kopfschüttel...).

Die Erklärung ist ganz einfach. Stell Dir vor, Du möchtest $1 als Index zu einem Array verwenden. Wenn Du nun das $-Zeichen weglässt, wäre aber über das Literal "1" immer das gleiche Element angesprochen... Da Du aber unzweideutig im Array-Kontext bist, muss eine Folge von Zeichen ein Variablenname sein. Die Shell ist dann eben so freundlich und denkt sich das "$" davor. Auch bei Rechnungen geht es so: Ob Du nun
(( START += DIS ))
oder
(( $START += $DIS ))
schreibst, ist egal.

> hm, ich habe in man bash sowas gesucht, es aber wohl übersehen.

Ja, der Teil ist schwer zu übersehen, owohl er da steht, wo er hingehört, nämlich unter "Arrays".

${#name[subscript]} expands to the length of ${name[sub-
script]}. If subscript is * or @, the expansion is the
number of elements in the array. Referencing an array
variable without a subscript is equivalent to referencing
element zero.


Ich schlage es auch manchmal nach, da ich es nicht jeden Tag benötige und überlese es dabei noch, obwohl ich weiss, wo es steht...

Jochen
 

rattengift
Gast





BeitragVerfasst am: 15. Dez 2002 21:56   Titel: Re: in BASH for schleife mit 2 laufvariablen

Hi Jochen,

> Ein für unsere Zwecke ausreichendes Minimal-seq ist mit bash-Mitteln schnell erstellt:

mhh, allmählich beschleicht mich das gefühl, dass die erste fassung (mit IFS) vielleicht doch die einfachste ist

> Die Erklärung ist ganz einfach.

leuchtet ein. danke!

> > hm, ich habe in man bash sowas gesucht, es aber wohl übersehen.
> da steht, wo er hingehört, nämlich unter "Arrays".

genau da hab ich es auch gesucht, es aber trotzdem übersehen. ein nachprüfen soeben ergab, dass es aber bei mir tatsächlich auch da steht. der abschnitt ist (selbst für manpage-verhältnisse) reichlich übersichtlich.
 

Beiträge vom vorherigen Thema anzeigen:   
     Pro-Linux Foren-Übersicht -> Programmieren - Allgemein Alle Zeiten sind GMT + 1 Stunde
Seite 1 von 1

 
Gehen Sie zu:  

Powered by phpBB © phpBB Group
pro_linux Theme © 2004 by Mandaxy