Pour obtenir la même sortie que vous notez dans votre question, tout ce qui est nécessaire est le suivant:
PS1='${PS2c##*[$((PS2c=0))-9]}- > '
PS2='$((PS2c=PS2c+1)) > '
Vous n'avez pas besoin de se contorsionner. Ces deux lignes feront tout dans n'importe quel shell qui prétend être proche de la compatibilité POSIX.
- > cat <<HD
1 > line 1
2 > line $((PS2c-1))
3 > HD
line 1
line 2
- > echo $PS2c
0
Mais j'ai aimé ça. Et je voulais démontrer les principes fondamentaux de ce qui rend ce travail un peu meilleur. J'ai donc édité ça un peu. Je l'ai coincé /tmp
pour l'instant mais je pense que je vais aussi le garder pour moi. C'est ici:
cat /tmp/prompt
ÉCRITURE RAPIDE:
ps1() { IFS=/
set -- ${PWD%"${last=${PWD##/*/}}"}
printf "${1+%c/}" "$@"
printf "$last > "
}
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
PS2='$((PS2c=PS2c+1)) > '
Remarque: ayant récemment appris le yash , je l'ai construit hier. Pour une raison quelconque, il n'imprime pas le premier octet de chaque argument avec la %c
chaîne - bien que les documents soient spécifiques sur les extensions à caractères larges pour ce format et donc il peut être lié - mais cela fonctionne très bien avec%.1s
Voilà tout. Il y a deux choses principales qui se passent là-haut. Et voici à quoi ça ressemble:
/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
Chaque fois qu'il $PS1
est évalué, il analyse et imprime $PWD
pour s'ajouter à l'invite. Mais je n'aime pas que tout le monde $PWD
encombre mon écran, donc je veux juste la première lettre de chaque fil d'Ariane dans le chemin actuel vers le répertoire actuel, que j'aimerais voir en entier. Comme ça:
/h/mikeserv > cd /etc
/etc > cd /usr/share/man/man3
/u/s/m/man3 > cd /
/ > cd ~
/h/mikeserv >
Il y a quelques étapes ici:
IFS=/
nous allons devoir diviser le courant $PWD
et le moyen le plus fiable de le faire est de le $IFS
diviser /
. Plus besoin de s'en préoccuper par la suite - tout fractionnement à partir d'ici sera défini par le $@
tableau de paramètres positionnels du shell dans la commande suivante, comme:
set -- ${PWD%"${last=${PWD##/*/}}"}
Donc celui-ci est un peu délicat, mais l'essentiel est que nous nous séparons $PWD
sur les /
symboles. J'utilise également l'expansion des paramètres pour $last
tout affecter après toute valeur se produisant entre la /
barre oblique la plus à gauche et la plus à droite . De cette façon, je sais que si je suis juste au point /
et que je n'en ai qu'un, /
il $last
sera toujours égal à l'ensemble $PWD
et $1
sera vide. C'est important. Je me déshabille également $last
de l'extrémité arrière $PWD
avant de l'attribuer $@
.
printf "${1+%c/}" "$@"
Donc, ici - tant que ${1+is set}
nous sommes printf
le premier caractère %c
de chacun des arguments de notre shell - que nous venons de définir pour chaque répertoire de notre répertoire actuel $PWD
- moins le répertoire supérieur - divisé /
. Nous n'imprimons donc essentiellement que le premier caractère de chaque répertoire, $PWD
mais le premier. Il est cependant important de réaliser que cela ne se produit que si la valeur $1
est définie, ce qui ne se produira pas à la racine /
ou à une suppression de /
comme dans /etc
.
printf "$last > "
$last
est la variable que je viens d'affecter à notre répertoire principal. Alors maintenant, c'est notre meilleur répertoire. Il affiche si oui ou non la dernière instruction a fait. Et il en faut un peu >
pour faire bonne mesure.
MAIS QU'EN EST-IL DE L'AUGMENTATION?
Et puis il y a la question du $PS2
conditionnel. J'ai montré plus tôt comment cela peut être fait, que vous pouvez toujours trouver ci-dessous - c'est fondamentalement une question de portée. Mais il y a un peu plus à moins que vous ne vouliez commencer à faire un tas d' printf \b
ackspaces et ensuite essayer d'équilibrer leur nombre de personnages ... ugh. Alors je fais ça:
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
Encore une fois, ${parameter##expansion}
sauve la mise. C'est un peu étrange ici cependant - nous définissons en fait la variable pendant que nous la supprimons d'elle-même. Nous utilisons sa nouvelle valeur - définie à mi-bande - comme le globe à partir duquel nous nous retirons. Tu vois? Nous ##*
supprimons tout de la tête de notre variable d'incrémentation au dernier caractère qui peut être n'importe quoi [$((PS2c=0))-9]
. Nous sommes ainsi garantis de ne pas afficher la valeur, et pourtant nous l'attribuons toujours. C'est plutôt cool - je n'ai jamais fait ça avant. Mais POSIX nous garantit également que c'est la manière la plus portable de procéder.
Et c'est grâce à POSIX-spécifié ${parameter} $((expansion))
qui conserve ces définitions dans le shell actuel sans exiger que nous les définissions dans un sous-shell séparé, quel que soit l'endroit où nous les évaluons. Et c'est pourquoi cela fonctionne dans dash
et sh
aussi bien que dans bash
et zsh
. Nous n'utilisons aucun échappement dépendant du shell / terminal et nous laissons les variables se tester. C'est ce qui rend le code portable rapide.
Le reste est assez simple - il suffit d'incrémenter notre compteur à chaque fois qu'il $PS2
est évalué jusqu'à ce qu'il soit $PS1
à nouveau réinitialisé. Comme ça:
PS2='$((PS2c=PS2c+1)) > '
Alors maintenant, je peux:
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
Cela fonctionne de la même manière dans bash
ou 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
Comme je l'ai dit ci-dessus, le principal problème est que vous devez considérer où vous effectuez votre calcul. Vous n'obtenez pas l'état dans le shell parent - vous n'y calculez donc pas. Vous obtenez l'état dans le sous-shell - c'est donc là que vous calculez. Mais vous faites la définition dans le shell parent.
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
.