Ich habe ein Bash-Skript geschrieben und zufällig den Code aktualisiert (die Skriptdatei auf der Festplatte gespeichert), während das Skript auf eine Eingabe in einer while
Schleife wartete . Nachdem ich zum Terminal zurückgekehrt war und mit dem vorherigen Aufruf des Skripts fortgefahren war, gab bash einen Fehler bezüglich der Dateisyntax aus:
/home/aularon/bin/script: line 58: unexpected EOF while looking for matching `"'
/home/aularon/bin/script: line 67: syntax error: unexpected end of file
Also habe ich Folgendes versucht:
1. Erstellen Sie ein Skript, nennen self-update.sh
wir es:
#!/bin/bash
fname=$(mktemp)
cat $0 | sed 's/BEFORE\./AFTER!./' > $fname
cp $fname $0
rm -f $fname
echo 'String: BEFORE.';
Das Skript liest seinen Code, ändert das Wort "VOR" in "NACH" und schreibt sich dann mit dem neuen Code neu.
2. Führen Sie es aus:
chmod +x self-update.sh
./self-update.sh
3. Wunder ...
aularon@aularon-laptop:~$ ./self-update.sh
String: AFTER!.
Nun, ich hätte nicht gedacht, dass bei demselben Aufruf NACH! sicher beim zweiten Lauf, aber nicht beim ersten.
Meine Frage ist also: Ist es beabsichtigt (beabsichtigt)? oder liegt es an der Art und Weise, wie bash das Skript ausführt? Zeile für Zeile oder Befehl für Befehl. Gibt es eine gute Verwendung eines solchen Verhaltens? Ein Beispiel dafür?
Bearbeiten: Ich habe versucht, die Datei neu zu formatieren, um alle Befehle in eine Zeile zu setzen. Es funktioniert jetzt nicht:
#!/bin/bash
fname=$(mktemp);cat $0 | sed 's/BEFORE\./AFTER!./' > $fname;cp $fname $0;rm -f $fname;echo 'String: BEFORE.';
Ausgabe:
aularon@aularon-laptop:~$ ./self-update.sh #First invocation
String: BEFORE.
aularon@aularon-laptop:~$ ./self-update.sh #Second invocation
String: AFTER!.
Wenn Sie die echo
Zeichenfolge in die nächste Zeile verschieben, trennen Sie sie vom cp
Aufruf von rewriting ( ):
#!/bin/bash
fname=$(mktemp);cat $0 | sed 's/BEFORE\./AFTER!./' > $fname;cp $fname $0;rm -f $fname;
echo 'String: BEFORE.';
Und jetzt funktioniert es wieder:
aularon@aularon-laptop:~$ ./self-update.sh
String: AFTER!.
Antworten:
Dies ist beabsichtigt. Bash liest Skripte in Stücken. Es liest also einen Teil des Skripts, führt alle möglichen Zeilen aus und liest dann den nächsten Block.
Sie stoßen also auf so etwas:
Noch problematischer wird dies, wenn Sie etwas vor Byte 256 bearbeiten. Nehmen wir an, Sie löschen ein paar Zeilen. Dann befinden sich die Daten im Skript, die sich bei Byte 256 befanden, jetzt an einer anderen Stelle, beispielsweise bei Byte 156 (100 Bytes früher). Wenn bash weiter liest, wird es aus diesem Grund das bekommen, was ursprünglich 356 war.
Dies ist nur ein Beispiel. Bash liest nicht unbedingt 256 Bytes gleichzeitig. Ich weiß nicht genau, wie viel es gleichzeitig liest, aber es spielt keine Rolle, das Verhalten ist immer noch dasselbe.
quelle
stat
die Datei, um zu sehen, ob sie geändert wurde. Keinelseek
Anrufe.echo foo
auf eine veränderteecho bar
während dersleep
. Es hat sich schon seit Version 2 so verhalten, daher denke ich nicht, dass es sich um ein Versionsproblem handelt.