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

while und IFS

Moin Moin,

war ja klar das die ersten Fragen nicht lange auf sich warten lassen...
Wenn ich in einer while-Schleife die Variable IFS ändere dann sieht es für mich so aus als würde diese Variable nach Beenden der Schleife wieder auf ihren alten Wert zurück gesetzt werden.
Beispiel schrieb:
while IFS=$'\n' read line
do
[...]
done < datei
echo "$IFS" | cat -vte
liefert mir
was aussagt das Leerzeichen, vertikal Tabs und newline die Seperatoren sind die in IFS dann drin sind. Aber warum ist das so? Warum wird IFS da nicht als globale Variable gehandhabt und behält damit nur das newline als Inhalt?
 
Bei "Variable=value Befehl" wird die Variable nur für den Befehl gesetzt.
In der nächsten Zeile ist die Variable wieder weg.
So interpretiere ich "IFS=$'\n' read line"

"Variable=value ; Befehl" setzt die Variable nicht nur für Befehl

Haveaniceday
 
A

Anonymous

Gast
haveaniceday schrieb:
Bei "Variable=value Befehl" wird die Variable nur für den Befehl gesetzt.
In der nächsten Zeile ist die Variable wieder weg.

IFS ist ein interne Bash Variable, Du kannst sie für verschiedene Funktionen wie auch jede andere Umgebungsvariabele nach der oben gezeigten Methode für die Laufzeit dieser Funktion oder dieses Befehle oder der gestarteten Subshell ändern. Diese Variable komplett in der Bash auf einen anderen Wert zu setzen, würde nur sehr gezielt einen Sinn machen zB innerhalb eines Scriptes, das aber dann genau auf diese Besonderheit aufgebaut sein muss.
Diese Variable zB in einer interaktiven Shell umsetzen und dort würde wahrscheinlich wenn überhaupt noch die Hälfte wie gewohnt funktionieren, zu viel ist von dieser Variable abhängig, zB können dann eventuell Optionen für Befehlen nicht mehr wie gewohnt aufgelöst werden, oder Aliase führen zu Fehlermeldungen und der gleichen mehr.
manpage bash schrieb:
The Internal Field Separator that is used for word splitting after expansion and to split lines into words with the read builtin command. The default value is ``<space><tab><newline>''

Nur mal so ein kleiner Selbst-Versuch was passiert kann, wenn man an diese Variable rumspielt ;)
Code:
rob-linux:~ # ls -l *.txt
-rw-r--r-- 1 root root 1044 Oct  2  2010 Packman-Pakete.txt
-rw-r--r-- 1 root root  298 Aug  8  2010 antwort.txt
-rw-r--r-- 1 root root  999 Nov 28  2010 libs.txt
-rw-r--r-- 1 root root 1725 Oct 15  2010 mail.txt
rob-linux:~ # IFS="[\n ;\t]"
rob-linux:~ # ls
ls: ambiguous argument `' for `--color'
Valid arguments are:
  - `always', `yes', `force'
  - `never', `no', `none'
  - `auto', `tty', `if-tty'
Try `ls --help' for more information.
rob-linux:~ # ls -l *.txt
ls: ambiguous argument `' for `--color'
Valid arguments are:
  - `always', `yes', `force'
  - `never', `no', `none'
  - `auto', `tty', `if-tty'
Try `ls --help' for more information.
es geht rein gar nichts mehr bei einigen normalen und ganz gewöhnlichen Befehlen, Fehlermeldungen ohne Ende und kein Hinweis wo der Fehler zu suchen ist, da bleibt oft nur noch "exit" für eine solche Shell ) ;) ;) ;) ;) ;)

robi
 
OP
Geier0815

Geier0815

Guru
Zu deinem Experiment: Wenn Du das alias für ls weg läßt das unter suse per default gesetzt ist, dürfte die Fehlermeldung so nicht mehr auftauchen. Denn color unter ls ist eine Option und wenn Du sie nicht im Befehl setzt, muß sie per alias gesetzt sein. Aber mir ist schon klar was Du damit zeigen willst. Wer soetwas nicht im Hinterkopf hat, kann ganz schön blöde Augen machen.

Aber davon jetzt ab. IFS wird also in der verwendeten Form auf den read-Befehl angewandt, allerdings nur auf die Laufzeit des Befehls und hat letztlich nichts mit der while-Schleife zu tun? Hab ich das richtig verstanden? Ich hatte zuerst nämlich vermutet das die Schleife quasi eine sub-shell erzeugt und der scope der Variable damit nicht auf den Eltern-Prozess zurück reicht. In meinem speziellen Fall hatte ich den gesamten Ausdruck eh in einer Funktion drin und damit die Variable "gekapselt", hab dann aber wegen experimenten mit Leerzeichen beim Einlesen, Manipulieren und Schreiben von Dateien das Ganze in einem eigenen Script getestet und mir dann erst Gedanken um die Reichweite der Variablen gemacht. Nun bin ich wieder mal etwas schlauer. Und ehrlich? Bash-Scripting erscheint mir teilweise deutlich vertrackter als Perl zumindest beim Einstieg.
 
A

Anonymous

Gast
Code:
VARIABLE="xyz" ; BEFEHL
hierbei sind das durch das ";" 2 Befehlsaufrufe, Die Variable wird global in der Shell gesetzt , die nächsten Befehle sehen diese Variable auch noch

Code:
VARIABLE="xyz" BEFEHL
Das ist nur ein Befehlsaufruf. Die Variable und der gesetzte Inhalt wirken nur auf die Umgebung dieses Befehls, der nächste Befehl sieht diese Variable oder den so gesetzten Inhalt nicht mehr.

Bei der While-Schleifen musst du in Punkto Subshells ein bischen aufpassen ob du eine Pipe verwendest oder nicht :???:
Code:
while read V
do
.......
done < datei
Hier wird die while Schleife in der aktuellen Shell ausgeführt, das heißt Variablen die in der Schleife gesetzt werden sind hinter der Schleife noch mit diesen Werten belegt.

allerdings
Code:
cat datei | while read V
do
......
done
Diese While Schleife wird in einer Subshell abgearbeitet, das bedeutet setzt du hier eine Variable innerhalb der Schleife kannst du hinter der Schleife nicht mehr darauf zugreifen.

Und ehrlich? Bash-Scripting erscheint mir teilweise deutlich vertrackter als Perl zumindest beim Einstieg.
Das stimmt leider, man braucht seine Zeit um ein Gefühl und Gespür für die Fein- und Eigenheiten zu bekommen, wenn man denn wirklich damit programmieren will.


robi
 
OP
Geier0815

Geier0815

Guru
Moin robi,

ich danke dir für deine Erklärungen und deine Geduld. Allerdings werfen sie bei mir noch eine Frage auf. Warum wirkt bei
Code:
VARIABLE="xyz" BEFEHL
die Variable wie eine Option und wird dann trotzdem nicht hinter dem Befehl geschrieben? Oder ist dabei der Befehl eine Option des Variablensetzens?

@haveaniceday,

selbstverständlich danke ich auch dir!
 

TomcatMJ

Guru
*kurz mal dazwischenquatsch* Hm, ich würde es so beschreiben: Die Variablensetzung vor dem Befehl modifiziert vorrübergehend erstmal die Umgebung in der der Befehl dann ausgeführt wird. Nach Beendigung des Befehls wird der Ausgangszustand dann wiederhergestellt. Daher wäre es relativ sinnfrei die Umgebung nach Ausführung des Befehls vorrübergehend zu modifizieren, da es dann ja schon zu späte für die beabsichtigte Wirkung wäre.
 

abgdf

Guru
robi schrieb:
IFS ist ein interne Bash Variable, Du kannst sie für verschiedene Funktionen wie auch jede andere Umgebungsvariabele nach der oben gezeigten Methode für die Laufzeit dieser Funktion oder dieses Befehle oder der gestarteten Subshell ändern. Diese Variable komplett in der Bash auf einen anderen Wert zu setzen, würde nur sehr gezielt einen Sinn machen zB innerhalb eines Scriptes, das aber dann genau auf diese Besonderheit aufgebaut sein muss.
Sowas macht man oft in Perl, siehe z.B.

http://birmingham.pm.org/talks/barbie/psv01/slide303.html

Steht so ähnlich auch in der offiziellen Dokumentation "perldoc perlvar" unter "$INPUT_RECORD_SEPARATOR".

In bash ist das wohl eher weniger gebräuchlich.
 
A

Anonymous

Gast
Geier0815 schrieb:
Warum wirkt bei
Code:
VARIABLE="xyz" BEFEHL
die Variable wie eine Option und wird dann trotzdem nicht hinter dem Befehl geschrieben? Oder ist dabei der Befehl eine Option des Variablensetzens?

ob nun vor dem Befehl oder dahinter ist wahrscheinlich sogar egal, (Ausgabeumlenkungen können auch vor oder hinter dem Befehl stehen, und bewirken dort genau das gleiche,) allerdings würde es bei den allermeisten Befehlen sehr kompliziert werden solche Variablezuweisungen hinter dem Befehl davor zu bewahren als Optionen für den Befehl interpretiert zu werden. Einige Befehle gehorchen auf eine spezielle Option "--" die das Ende der Optionsliste festlegt.
müsste man mal bei einem solchem Befehl ausprobieren ob dahinter auch noch Variable Zuweisungen möglich sind. Ließt sich aber bestimmt extrem abartig.
Werde heute abend mal ein bisschen testen, jetzt lass ich mir aber erstmal ne Pizza in den Ofen schieben ;) ;) ;)

robi

PS:
ob nun vor dem Befehl oder dahinter ist wahrscheinlich sogar egal
stimmt nicht zeigen mein Tests, war mir so auch nicht bewusst, das muss zwingend vor dem Befehl stehen, sonst geht es nicht.
Steht auch so (wenn auch mehr zwischen den Zeilen) in der Manpage
man bash schrieb:
The environment for any simple command or function may be augmented temporarily by prefixing it with parameter assignments, as described above in PARAMETERS. These assignment statements affect only the environment seen by that command.

robi
 
Oben