Diese Website existiert nur weil wir Werbung mit AdSense ausliefern.
Bitte den AdBlocker daher auf dieser Website ausschalten! Danke.
Bitte den AdBlocker daher auf dieser Website ausschalten! Danke.
Zähler nach einer while-Schleife behalten
Moderator: Moderatoren
-
- Member
- Beiträge: 110
- Registriert: 12. Sep 2017, 10:25
Zähler nach einer while-Schleife behalten
Hallo,
da eine while-Schleife in einer eigenen Subshell läuft, ist der Zähler nachdem die Schleife durchlaufen ist wieder weg. Wie kann ich den weiter nutzen? Spontan fällt mir nur ein den Zähler in eine Textdatei zu exportieren.
bf
da eine while-Schleife in einer eigenen Subshell läuft, ist der Zähler nachdem die Schleife durchlaufen ist wieder weg. Wie kann ich den weiter nutzen? Spontan fällt mir nur ein den Zähler in eine Textdatei zu exportieren.
bf
Re: Zähler nach einer while-Schleife behalten
Du kannst den Wert des Zählers in der Subshell zurückgeben.
Hast Du einen Codesnippet den Du uns zeigen kannst?
Hast Du einen Codesnippet den Du uns zeigen kannst?
-
- Member
- Beiträge: 110
- Registriert: 12. Sep 2017, 10:25
Re: Zähler nach einer while-Schleife behalten
Ich will ihn ja nicht in der Subshell wiedergeben, ich will ihn danach weiter nutzen.
Zum einen soll jede Schleife wieder bei i=0 beginnen mit ihrem Durchlauf und entsprechend oft laufen. WEnn also var1=1 und var2=2 sind, würde die erste Schleife einen und die zweite Schleife 2 Durchläufe machen. Am Ende soll zusätzlich noch eine Variable $summe angeben wieviel Durchläufe insgesamt durchlaufen sind. Nach Schleife 1 müsste $summe also 1 und nach Schleife 2 3 sein.
Code: Alles auswählen
i=0
while [ $i -lt $var1 ]; do
echo "$i"
i=`expr $i + 1`
done
i=0
while [ $i -lt $var2 ]; do
echo "$i"
i=`expr $i + 1`
done
echo "$summe"
-
- Hacker
- Beiträge: 624
- Registriert: 23. Jun 2008, 20:51
Re: Zähler nach einer while-Schleife behalten
Das sieht seltsam aus, was du da machst!
Ich habe es nicht getestet
Code: Alles auswählen
#!/bin/bash
x_test()
{
local i s=0 va="$1" vb="$2"
for((i=0; i < $va; i++,s++)); do
printf "i = %d\n" "$i"
done
for((i=0; i < $vb; i++,s++)); do
printf "i = %d\n" "$i"
done
printf "s = %d\n" "$s"
return 0
}
x_test 1 2
exit 0
Re: Zähler nach einer while-Schleife behalten
entsprechend deinem geschilderten Ablaufarithmetik im Script ist bei dir summe immer (va + vb), warum willst du das unnötig verkomplizieren in dem du unnötig versucht Variablen über Subshellgrenzen zu transponieren?bunter fisch hat geschrieben: ↑21. Jun 2019, 18:57 Am Ende soll zusätzlich noch eine Variable $summe angeben wieviel Durchläufe insgesamt durchlaufen sind. Nach Schleife 1 müsste $summe also 1 und nach Schleife 2 3 sein.
robi
Re: Zähler nach einer while-Schleife behalten
Manchmal helfen da geschleifte Klammern.bunter fisch hat geschrieben: ↑21. Jun 2019, 18:57Ich will ihn ja nicht in der Subshell wiedergeben, ich will ihn danach weiter nutzen.
Aber insgesamt ist das sicher ein Punkt, an dem die Shell mir nur wenig kontrollierbar scheint (und selbst Seiten wie der "Advanced Bash-Scripting Guide" helfen da nicht wirklich weiter).
Ich würde Dir daher raten, Dir mal Perl anzugucken. Das verhält sich in dem Punkt nämlich konsequent vorhersehbar.
Code: Alles auswählen
#!/usr/bin/perl
use warnings;
use strict;
my $var1 = 1;
my $var2 = 2;
my $summe = 0;
my $i = 0;
while ($i < $var1) {
print "$i\n";
$i++;
$summe++;
}
$i = 0;
while ($i < $var2) {
print "$i\n";
$i++;
$summe++;
}
print "$summe\n";
Re: Zähler nach einer while-Schleife behalten
Das stimmt so pauschal erstmal nicht.bunter fisch hat geschrieben: ↑21. Jun 2019, 14:48 da eine while-Schleife in einer eigenen Subshell läuft, ist der Zähler nachdem die Schleife durchlaufen ist wieder weg.
Code: Alles auswählen
i=0; while [ $i -lt 9 ]; do echo "intern = $i"; i=$(($i+1)); done ; echo "extern = $i"
intern = 0
intern = 1
intern = 2
intern = 3
intern = 4
intern = 5
intern = 6
intern = 7
intern = 8
extern = 9
Allerdings, kleine Abwandlung, ich starte die while-Schleife in einer Pipe und übergebe ihr in der Pipe die Ausgabe von "echo hallo"
Code: Alles auswählen
i=0; echo hallo | while [ $i -lt 9 ]; do read D ; echo "intern = $i $D "; i=$(($i+1)); done ; echo "extern = $i"
intern = 0 hallo
intern = 1
intern = 2
intern = 3
intern = 4
intern = 5
intern = 6
intern = 7
intern = 8
extern = 0
Sowas kann man in der Bash versuchen zu umgehen, indem man versucht das in der Subshell zu startet, von wo man später zB keine Variable mehr braucht. Also in unseren Fall nicht das "echo hallo" in der aktuellen Shell und die While-Schleife in der Subshell, sondern genau anders herum.
Die While-Schleife in der aktuellen Shell und das "echo hallo" ausgelagert in eine Subshell , zB.:
Code: Alles auswählen
i=0; while [ $i -lt 9 ]; do read D ; echo "intern = $i $D "; i=$(($i+1)); done < <(echo hallo) ; echo "extern = $i"
intern = 0 hallo
intern = 1
intern = 2
intern = 3
intern = 4
intern = 5
intern = 6
intern = 7
intern = 8
extern = 9
robi
Re: Zähler nach einer while-Schleife behalten
Und das ist genau das Problem: In manchen Situationen sind solche Variablen dann noch da, und manchmal sind sie weg. Ein exaktes Muster, wann das so und wann das anders passiert, kann ich nicht erkennen.robi hat geschrieben:Das stimmt so pauschal erstmal nicht.
Wenn Du das Muster dafür beschreiben kannst, wäre ich ganz Ohr.
Re: Zähler nach einer while-Schleife behalten
@abgdf Es ist in der bash definiert: Eine Subshell kann Variablen der Parentshell nicht aendern.
@robi hat Beispiele gegeben in dem
1) Das Beispiel des TEs etwas erweitert und es so funktioniert wie Du es in perl tust da keine Subshell benutzt wird
2) Ein Beispiel gegeben wo eine Subshell benutzt wird und es deshalb nicht funktioniert (eine Pipe läuft in einer Subshell)
3) Ein Beispiel in bash gegeben wie man das Problem in (2) umgeben kann
@robi hat Beispiele gegeben in dem
1) Das Beispiel des TEs etwas erweitert und es so funktioniert wie Du es in perl tust da keine Subshell benutzt wird
2) Ein Beispiel gegeben wo eine Subshell benutzt wird und es deshalb nicht funktioniert (eine Pipe läuft in einer Subshell)
3) Ein Beispiel in bash gegeben wie man das Problem in (2) umgeben kann
Re: Zähler nach einer while-Schleife behalten
Beispiele sind schonmal gut. Dann würde mich noch die allgemeine Regel interessieren, wo das Problem auftritt und wo nicht.framp hat geschrieben: ↑22. Jun 2019, 20:10robi hat Beispiele gegeben in dem
1) Das Beispiel des TEs etwas erweitert und es so funktioniert wie Du es in perl tust da keine Subshell benutzt wird
2) Ein Beispiel gegeben wo eine Subshell benutzt wird und es deshalb nicht funktioniert (eine Pipe läuft in einer Subshell)
3) Ein Beispiel in bash gegeben wie man das Problem in (2) umgeben kann
In welchen Fällen kommt es zur Eröffnung einer Subshell?
Was passiert, wenn sie schließt?
Kann man Variablen aus der Subshell zur Weiterverarbeitung in die übergeordnete Shell übertragen (was ja wohl auch die Frage des TE war)?
Was ist eine Subshell überhaupt?
Wie steuert die Hauptshell die Subshell?
Wie funktioniert die Übergabe von Variablen aus der Hauptshell an die Subshell?
Kann man auch Arrays übertragen (in die Subshell, aus der Subshell)?
Oder vielleicht Referenzen auf Datenstrukturen?

Erzeugt jeder Schleifendurchlauf eine eigene Subshell? Oder eine while-Schleife insgesamt nur eine Subshell?
Gibt es eine maximale Anzahl von Subshells?
Kann man Kommandos an die Subshell übertragen, während sie läuft (vgl. subprocess-Modul in Python)?
Was hat es mit den geschweiften Klammern in bash auf sich, und warum kann man damit manchmal Subshells unterbinden, obwohl sie doch eigentlich erforderlich sein müßten (sonst wären sie ja überflüssig)?
Es bleibt also noch Vieles, was noch nicht so ganz klar ist.
Re: Zähler nach einer while-Schleife behalten
Die einfache Antwort wird dir nicht gefallen : 42
Alles andere ist gar nicht so schrecklich kompliziert, aber bestimmt alles andere als einfach zu erklären und wird wohl auch nicht in wenigen Zeilen zu erledigen sein.
Lasst mir mal ein bisschen Zeit, ich versuch mal einen Wiki-Beitrag zu dem Thema zu erstellen, ich denke das ist Allgemein und als Referenz durchaus von Interesse.
Das soll aber nicht heißen dass ihr solange warten müsst, bitte hier im Forum weiter diskutieren und auch schon versuchen Teile davon zu beantworten damit ich noch ein bisschen mehr Stoff und Anregungen für den Zusammenbau des Wiki-Beitrags bekomme. Wer jetzt im Forum schon Teilantworten hat, oder weiteres hierzu brauchbares, Halbfertiges zuliefern kann immer her damit, auch weitere Fragen in diesem Zusammenhang sind noch willkommen.
Notfalls schneiden wir das dann hier aus dem Thread raus und machen einen eigenen Thread daraus, damit es übersichtlich bleibt.
robi
Re: Zähler nach einer while-Schleife behalten
Whow ... das sind eine Menge Fragen.
1) per echo
2) per printf -v Option
Ich kenne zwei Wege:Kann man Variablen aus der Subshell zur Weiterverarbeitung in die übergeordnete Shell übertragen?
1) per echo
2) per printf -v Option
Code: Alles auswählen
#!/bin/bash
add1() { # add two numbers and return result via echo
echo $(( $1 + $2 ))
}
add2() { # add two numbers and return result in variable, name passed in first parm
local r
(( r = $2 + $3 ))
printf -v $1 "%s" $r
}
testData=("1 2" "3 4" "5 6")
result=""
for d in "${testData[@]}"; do
read -r a b <<< "$d"
echo "add1: $a + $b = $(add1 $a $b)"
add2 result $a $b
echo "add2: $a + $b = $result"
done
Re: Zähler nach einer while-Schleife behalten
Wenn du aufzeigen willst wie man Variablen aus einer Subshell in der übergeordneten Shell weiterverarbeite kann, musst du aber wenigstens eine übergeordenet Shell und eine Subshell zur Demonstration verwenden

Dein Beispielscript arbeitet alles in einer einzigen Shell ab auch die Funktionen, du sagst zwar die Variable r, soll nur innerhalb der Funktion gültig sein, das ist etwas anderes als eine Subshell. locale und globale Variablen gibts in fast jeder Programmiersprache.
einfach mal die "local r" Deklaration aus der add2() auskommentieren,
und schon kannst du ganz am Ende vom Script mit "echo $r" auf die Variable zugreifen die in der Funktion add2() gesetzt wird und wirst bei deinem Beispieldaten 11 erhalten. Das wäre nicht möglich, wenn die Funktion in einer Subshell abgearbeitet wird, weil dann die Variableinhalte aus der Subshell nicht mehr vorhanden sind, sobald die Subshell endet.
Ich sage nicht um sonst, es ist nicht ganz so leicht es einigermaßen verständlich zu erklären.

robi
Re: Zähler nach einer while-Schleife behalten
Offensichtlich hatte ich ein falsches Verstaendnis von subshells



-
- Hacker
- Beiträge: 624
- Registriert: 23. Jun 2008, 20:51
Re: Zähler nach einer while-Schleife behalten
Ihr verwechselt hier etwas Grundsätzliches.
Beiliegend ein Beispiel von reinen Subshells.
main() ist die Konsole selbst, in der der user eine SHELL aufruft.
Diese SHELL startet EINE sub_shell, die ihrerseits jedesmal eine NEUE sub_shell erzeugt. (nested sub_shell)
Bitte auf pid und parent_pid achten, die sich auch bei nested sub_shells immer auf main() als parent UND das PID auf die SHELL beziehen.
Es findet kein fork statt, $BASHPID ist nur ein künstliches Konstrukt und so auch jede sub_shell. Jede andere Form sind sub_processes mit
dem Resultat eines eigenen PIDs und parent auf SHELL und nicht main(). Das kann sein ein fork(), ein thread() oder ein simpler call nach system();
Am Beispiel TE wird unnötigerweise ein sub_process gestartet. Auch read() tut das, selbst wenn als "internes Kommando" deklariert.
Dieser Unterschied sollte beachtet werden.
Gruß
Gräfin Klara
Beiliegend ein Beispiel von reinen Subshells.
main() ist die Konsole selbst, in der der user eine SHELL aufruft.
Diese SHELL startet EINE sub_shell, die ihrerseits jedesmal eine NEUE sub_shell erzeugt. (nested sub_shell)
Bitte auf pid und parent_pid achten, die sich auch bei nested sub_shells immer auf main() als parent UND das PID auf die SHELL beziehen.
Es findet kein fork statt, $BASHPID ist nur ein künstliches Konstrukt und so auch jede sub_shell. Jede andere Form sind sub_processes mit
dem Resultat eines eigenen PIDs und parent auf SHELL und nicht main(). Das kann sein ein fork(), ein thread() oder ein simpler call nach system();
Am Beispiel TE wird unnötigerweise ein sub_process gestartet. Auch read() tut das, selbst wenn als "internes Kommando" deklariert.
Dieser Unterschied sollte beachtet werden.
Code: Alles auswählen
#!/bin/bash
printf "main(%d): spawn shell %d\n" "$PPID" "$BASHPID"
printf " shell(%d): start subshells ..\n" "$$"
(
i=0
while((i++ < 3)); do
printf " subshell(%d): number %d, PID %d, parent %d\n" "$BASHPID" "$BASH_SUBSHELL" "$$" "$PPID"
sleep 1
(
while true; do
printf " subshell(%d): number %d, PID %d, parent %d\n" "$BASHPID" "$BASH_SUBSHELL" "$$" "$PPID"
sleep 1
break
done
)
done
)
printf " shell(%d): exit to main %d ..\n" "$$" "$PPID"
printf "EXIT\n"
exit 0
Gräfin Klara