Um die gleiche Ausgabe zu erhalten, die Sie in Ihrer Frage notiert haben, ist nur Folgendes erforderlich:
PS1='${PS2c##*[$((PS2c=0))-9]}- > '
PS2='$((PS2c=PS2c+1)) > '
Sie brauchen sich nicht zu verziehen. Diese beiden Zeilen funktionieren in jeder Shell, die eine POSIX-Kompatibilität vorgibt.
- > cat <<HD
1 > line 1
2 > line $((PS2c-1))
3 > HD
line 1
line 2
- > echo $PS2c
0
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:
cat /tmp/prompt
PROMPT SCRIPT:
ps1() { IFS=/
set -- ${PWD%"${last=${PWD##/*/}}"}
printf "${1+%c/}" "$@"
printf "$last > "
}
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
PS2='$((PS2c=PS2c+1)) > '
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:
/u/s/m/man3 > cat <<HERE
1 > line 1
2 > line 2
3 > line $((PS2c-1))
4 > HERE
line 1
line 2
line 3
/u/s/m/man3 >
PARSING $PWD
Jedes Mal, wenn $PS1
es ausgewertet wird, wird es analysiert und gedruckt $PWD
, um es der Eingabeaufforderung hinzuzufügen. Aber ich mag es nicht, wenn $PWD
mein Bildschirm voll ist, deshalb möchte ich nur den ersten Buchstaben jedes Breadcrumbs im aktuellen Pfad bis zum aktuellen Verzeichnis, das ich gerne vollständig sehen würde. So was:
/h/mikeserv > cd /etc
/etc > cd /usr/share/man/man3
/u/s/m/man3 > cd /
/ > cd ~
/h/mikeserv >
Hier gibt es ein paar Schritte:
IFS=/
Wir müssen den Strom aufteilen, $PWD
und der zuverlässigste Weg, dies zu tun, ist $IFS
Split on /
. Danach brauchen Sie sich überhaupt nicht mehr darum zu kümmern - alle Aufteilungen von hier an werden durch das Positionsparameter- $@
Array der Shell im nächsten Befehl wie folgt definiert :
set -- ${PWD%"${last=${PWD##/*/}}"}
Das ist ein bisschen knifflig, aber die Hauptsache ist, dass wir uns $PWD
auf /
Symbole aufteilen. Ich verwende auch die Parametererweiterung, um $last
nach jedem Wert, der zwischen dem /
Schrägstrich ganz links und ganz rechts liegt , alles zuzuweisen . Auf diese Weise weiß ich, dass wenn ich gerade dabei bin /
und nur einen habe, /
dann $last
immer noch das Ganze gleich ist $PWD
und $1
leer sein wird. Das ist wichtig. Ich entferne auch $last
das hintere Ende von, $PWD
bevor ich es zuordne $@
.
printf "${1+%c/}" "$@"
Also hier - solange ${1+is set}
wir printf
das erste %c
Zeichen der Argumente unserer Shell sind - das wir gerade auf jedes Verzeichnis in unserem aktuellen $PWD
- abzüglich des obersten Verzeichnisses - aufgeteilt haben /
. Wir drucken also im Wesentlichen nur das erste Zeichen jedes Verzeichnisses $PWD
außer dem obersten. Es ist jedoch wichtig zu wissen, dass dies nur dann geschieht, wenn $1
es überhaupt gesetzt wird, was nicht bei root /
oder bei einem, der von /
solchen wie in entfernt wird, der Fall ist /etc
.
printf "$last > "
$last
ist die Variable, die ich gerade unserem Hauptverzeichnis zugewiesen habe. Das ist also unser oberstes Verzeichnis. Es wird gedruckt, ob die letzte Anweisung dies tat oder nicht. Und es braucht ein ordentliches kleines >
Maß.
ABER WAS IST MIT DER ERHÖHUNG?
Und dann ist da noch die Sache mit der $PS2
Bedingung. Ich habe bereits früher gezeigt, wie dies gemacht werden kann. Dies ist grundsätzlich eine Frage des Umfangs. Aber es printf \b
steckt noch ein bisschen mehr dahinter, es sei denn, Sie möchten eine Reihe von Ackspaces erstellen und dann versuchen, die Anzahl ihrer Charaktere auszugleichen ... ugh. Also mache ich das:
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
Auch hier ${parameter##expansion}
spart der Tag. Hier ist es allerdings etwas seltsam - wir setzen die Variable tatsächlich, während wir sie selbst entfernen. Wir verwenden seinen neuen Wert - Set Mid-Strip - als Glob, von dem wir entfernen. Siehst du? Wir ##*
streifen alles vom Kopf unserer Inkrementvariablen bis zum letzten Zeichen ab, von dem alles sein kann [$((PS2c=0))-9]
. Auf diese Weise wird garantiert, dass der Wert nicht ausgegeben wird, und wir weisen ihn dennoch zu. Es ist ziemlich cool - das habe ich noch nie gemacht. POSIX garantiert uns aber auch, dass dies die portabelste Art ist, dies zu tun.
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 in dash
und sh
genauso gut wie in bash
und zsh
. 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:
PS2='$((PS2c=PS2c+1)) > '
So jetzt kann ich:
DASH DEMO
ENV=/tmp/prompt dash -i
/h/mikeserv > cd /etc
/etc > cd /usr/share/man/man3
/u/s/m/man3 > cat <<HERE
1 > line 1
2 > line 2
3 > line $((PS2c-1))
4 > HERE
line 1
line 2
line 3
/u/s/m/man3 > printf '\t%s\n' "$PS1" "$PS2" "$PS2c"
$(ps1)${PS2c##*[$((PS2c=0))-9]}
$((PS2c=PS2c+1)) >
0
/u/s/m/man3 > cd ~
/h/mikeserv >
SH DEMO
Es funktioniert genauso in bash
oder sh
:
ENV=/tmp/prompt sh -i
/h/mikeserv > cat <<HEREDOC
1 > $( echo $PS2c )
2 > $( echo $PS1 )
3 > $( echo $PS2 )
4 > HEREDOC
4
$(ps1)${PS2c##*[$((PS2c=0))-9]}
$((PS2c=PS2c+1)) >
/h/mikeserv > echo $PS2c ; cd /
0
/ > cd /usr/share
/u/share > cd ~
/h/mikeserv > exit
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.
ENV=/dev/fd/3 sh -i 3<<\PROMPT
ps1() { printf '$((PS2c=0)) > ' ; }
ps2() { printf '$((PS2c=PS2c+1)) > ' ; }
PS1=$(ps1)
PS2=$(ps2)
PROMPT
0 > cat <<MULTI_LINE
1 > $(echo this will be line 1)
2 > $(echo and this line 2)
3 > $(echo here is line 3)
4 > MULTI_LINE
this will be line 1
and this line 2
here is line 3
0 >
man 1 mktemp
.