Ich möchte eine Funktion in Bash implementieren, die bei jedem Aufruf die Anzahl erhöht (und zurückgibt). Leider scheint dies nicht trivial zu sein, da ich die Funktion in einer Subshell aufrufe und folglich die Variablen der übergeordneten Shell nicht ändern kann.
Hier ist mein Versuch:
PS_COUNT=0
ps_count_inc() {
let PS_COUNT=PS_COUNT+1
echo $PS_COUNT
}
ps_count_reset() {
let PS_COUNT=0
}
Dies würde wie folgt verwendet werden (und daher muss ich die Funktionen von einer Subshell aus aufrufen):
PS1='$(ps_count_reset)> '
PS2='$(ps_count_inc) '
Auf diese Weise hätte ich eine nummerierte mehrzeilige Eingabeaufforderung:
> echo 'this
1 is
2 a
3 test'
Süß. Aber aufgrund der oben genannten Einschränkung funktioniert nicht.
Eine nicht funktionierende Lösung wäre, die Anzahl in eine Datei anstatt in eine Variable zu schreiben. Dies würde jedoch zu einem Konflikt zwischen mehreren gleichzeitig ausgeführten Sitzungen führen. Ich könnte natürlich die Prozess-ID der Shell an den Dateinamen anhängen. Aber ich hoffe, es gibt eine bessere Lösung, die mein System nicht mit vielen Dateien überfrachtet.
man 1 mktemp
.Antworten:
Um die gleiche Ausgabe zu erhalten, die Sie in Ihrer Frage notiert haben, ist nur Folgendes erforderlich:
Sie brauchen sich nicht zu verziehen. Diese beiden Zeilen funktionieren in jeder Shell, die eine POSIX-Kompatibilität vorgibt.
Aber mir hat das gefallen. Und ich wollte die Grundlagen dafür demonstrieren, was diese Arbeit ein bisschen besser macht. Also habe ich das ein wenig bearbeitet. Ich habe es
/tmp
erstmal reingesteckt, aber ich denke, ich werde es auch für mich behalten. Es ist hier:PROMPT SCRIPT:
Hinweis: Nachdem ich kürzlich von Yash erfahren habe , habe ich es gestern gebaut. Aus irgendeinem Grund gibt es nicht das erste Byte jedes Arguments mit der
%c
Zeichenfolge aus - obwohl die Dokumente spezifisch für Wide-Char-Erweiterungen für dieses Format waren und es möglicherweise damit zusammenhängt -, aber es ist in Ordnung mit%.1s
Das ist die ganze Sache. Dort oben gehen zwei Dinge vor. Und so sieht es aus:
PARSING
$PWD
ABER WAS IST MIT DER ERHÖHUNG?
Dank POSIX
${parameter} $((expansion))
bleiben diese Definitionen in der aktuellen Shell, ohne dass wir sie in einer separaten Subshell festlegen müssen, unabhängig davon, wo wir sie auswerten. Und deshalb funktioniert es indash
undsh
genauso gut wie inbash
undzsh
. Wir verwenden keine Shell / Terminal-abhängigen Escapes und lassen die Variablen selbst testen. Das macht portablen Code schnell.Der Rest ist ziemlich einfach - erhöhen Sie einfach unseren Zähler für jedes Mal
$PS2
, wenn$PS1
er ausgewertet wird, bis er wieder zurückgesetzt wird. So was:So jetzt kann ich:
DASH DEMO
SH DEMO
Es funktioniert genauso in
bash
odersh
:Wie oben erwähnt, besteht das Hauptproblem darin, dass Sie sich überlegen müssen, wo Sie Ihre Berechnung durchführen. Sie erhalten den Status nicht in der übergeordneten Shell - also berechnen Sie dort nicht. Sie erhalten den Status in der Subshell - also rechnen Sie dort. Aber Sie machen die Definition in der übergeordneten Shell.
quelle
PS2
? Dies ist der schwierige Teil. Ich glaube nicht, dass Ihre Lösung hier angewendet werden kann. Wenn Sie anders denken, zeigen Sie mir bitte, wie.PS1
undPS2
sind spezielle Variablen in der Shell, die als Eingabeaufforderung ausgegeben werden (versuchen Sie es, indem SiePS1
in einem neuen Shell-Fenster einen anderen Wert festlegen). Sie werden daher ganz anders als Ihr Code verwendet. Hier einige weitere Informationen zu ihrer Verwendung: linuxconfig.org/bash-prompt-basicsecho 'this
an einer Eingabeaufforderung Folgendes ein und erläutern Sie, wie Sie den Wert von aktualisieren,PS2
bevor Sie das schließende einfache Anführungszeichen eingeben.Mit diesem Ansatz (Funktion wird in einer Subshell ausgeführt) können Sie den Status des Master-Shell-Prozesses nicht aktualisieren, ohne Verzerrungen zu durchlaufen. Sorgen Sie stattdessen dafür, dass die Funktion im Master-Prozess ausgeführt wird.
Der Wert der
PROMPT_COMMAND
Variablen wird als Befehl interpretiert, der vor dem Drucken derPS1
Eingabeaufforderung ausgeführt wird.Denn
PS2
es gibt nichts Vergleichbares. Sie können jedoch stattdessen einen Trick verwenden: Da Sie lediglich eine arithmetische Operation ausführen möchten, können Sie eine arithmetische Erweiterung verwenden, die keine Unterschale umfasst.Das Ergebnis der arithmetischen Berechnung endet in der Eingabeaufforderung. Wenn Sie es ausblenden möchten, können Sie es als Array-Index übergeben, der nicht vorhanden ist.
quelle
Es ist ein bisschen I / O-intensiv, aber Sie müssen eine temporäre Datei verwenden, um den Wert der Zählung zu halten.
Wenn Sie befürchten, eine separate Datei pro Shell-Sitzung zu benötigen (was als unbedeutend erscheint; werden Sie wirklich mehrzeilige Befehle in zwei verschiedenen Shells gleichzeitig eingeben?), Sollten Sie
mktemp
für jede eine neue Datei erstellen verwenden.quelle
Auf diese Weise können Sie keine Shell-Variable verwenden, und Sie wissen bereits, warum. Eine Subshell erbt Variablen genauso wie ein Prozess seine Umgebung: Alle vorgenommenen Änderungen gelten nur für sie und ihre untergeordneten Elemente und nicht für einen Vorgängerprozess.
Laut anderen Antworten ist es am einfachsten, diese Daten in einer Datei zu speichern.
Etc.
quelle
mktemp
. B. ).PS2
von der Shell erweitert wird. Zu diesem Zeitpunkt haben Sie keine Möglichkeit, den Wert einer Variablen in der übergeordneten Shell zu aktualisieren.Als Referenz hier meine Lösung mit temporären Dateien, die pro Shell-Prozess eindeutig sind und so schnell wie möglich gelöscht werden (um Unordnung zu vermeiden, wie in der Frage angedeutet):
quelle