
Para obtener el mismo resultado que anota en su pregunta, todo lo que se necesita es esto:
PS1='${PS2c##*[$((PS2c=0))-9]}- > '
PS2='$((PS2c=PS2c+1)) > '
No necesitas contorsionar. Esas dos líneas lo harán todo en cualquier shell que simule algo cercano a la compatibilidad POSIX.
- > cat <<HD
1 > line 1
2 > line $((PS2c-1))
3 > HD
line 1
line 2
- > echo $PS2c
0
Pero me ha gustado esto. Y quería demostrar los fundamentos de lo que hace que esto funcione un poco mejor. Así que edité esto un poco. Lo puse /tmppor ahora, pero creo que también me lo guardaré. Esta aquí:
cat /tmp/prompt
GUIÓN INMEDIATA:
ps1() { IFS=/
set -- ${PWD%"${last=${PWD##/*/}}"}
printf "${1+%c/}" "$@"
printf "$last > "
}
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
PS2='$((PS2c=PS2c+1)) > '
Nota: habiendo aprendido recientemente de yash , lo construí ayer. Por alguna razón, no imprime el primer byte de cada argumento con la %ccadena, aunque los documentos eran específicos sobre las extensiones de ancho ancho para ese formato y, por lo tanto, pueden estar relacionados, pero funciona bien con%.1s
Eso es todo. Hay dos cosas principales que suceden allí arriba. Y así es como se ve:
/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
Cada vez que $PS1se evalúa, se analiza e imprime $PWDpara agregar a la solicitud. Pero no me gusta que toda $PWDmi pantalla se llene, así que solo quiero la primera letra de cada ruta de navegación en la ruta actual hasta el directorio actual, que me gustaría ver en su totalidad. Me gusta esto:
/h/mikeserv > cd /etc
/etc > cd /usr/share/man/man3
/u/s/m/man3 > cd /
/ > cd ~
/h/mikeserv >
Aquí hay algunos pasos:
IFS=/
Vamos a tener que dividir la corriente $PWDy la forma más confiable de hacerlo es $IFSdividir /. No es necesario molestarse con eso después: toda la división de aquí en adelante se definirá por la $@matriz de parámetros posicionales del shell en el siguiente comando como:
set -- ${PWD%"${last=${PWD##/*/}}"}
Esto es un poco complicado, pero lo principal es que nos estamos dividiendo $PWDen /símbolos. También utilizo la expansión de parámetros para asignar a $lasttodo después de cualquier valor que ocurra entre la /barra diagonal izquierda y la derecha . De esta manera sé que si estoy justo en /y tienen un único /entonces $lasttodavía será igual a la totalidad $PWDy $1estará vacía. Esto importa También me quito $lastel extremo de la cola $PWDantes de asignarlo $@.
printf "${1+%c/}" "$@"
Entonces, aquí, siempre que ${1+is set}seamos printfel primer %cpersonaje de cada uno de los argumentos de nuestro shell, que acabamos de establecer en cada directorio de nuestro actual $PWD, menos el directorio superior, se divide /. Esencialmente, solo estamos imprimiendo el primer carácter de cada directorio, $PWDexcepto el superior. Sin embargo, es importante darse cuenta de que esto solo sucede si $1se establece, lo que no sucederá en la raíz /o en uno eliminado /, como en /etc.
printf "$last > "
$lastes la variable que acabo de asignar a nuestro directorio superior. Así que ahora este es nuestro directorio principal. Imprime si la última declaración lo hizo o no. Y se necesita un poco limpio >por si acaso.
¿Pero qué hay del incremento?
Y luego está el asunto de lo $PS2condicional. Mostré anteriormente cómo se puede hacer esto, que aún puede encontrar a continuación: esto es fundamentalmente una cuestión de alcance. Pero hay un poco más a menos que desees comenzar a hacer un montón de printf \bespacios y luego tratar de equilibrar su cuenta de personajes ... ugh. Entonces hago esto:
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
De nuevo, ${parameter##expansion}salva el día. Sin embargo, es un poco extraño aquí: en realidad establecemos la variable mientras la despojamos de sí misma. Usamos su nuevo valor, establecer mid-strip, como el glob del que nos despojamos. ¿Lo ves? Nos ##*despojamos de todo de la cabeza de nuestra variable de la subasta hasta el último carácter que puede ser cualquier cosa de [$((PS2c=0))-9]. De esta forma, tenemos la garantía de no generar el valor, y aún así lo asignamos. Es genial, nunca lo había hecho antes. Pero POSIX también nos garantiza que esta es la forma más portátil de hacerlo.
Y es gracias a POSIX-especificado ${parameter} $((expansion))que mantiene estas definiciones en el shell actual sin requerir que las establezcamos en un subshell separado, independientemente de dónde las evaluamos. Y es por eso que funciona en dashy shtan bien como en bashy zsh. No utilizamos escapes dependientes de shell / terminal y dejamos que las variables se prueben a sí mismas. Eso es lo que hace que el código portátil sea rápido.
El resto es bastante simple: solo incremente nuestro contador por cada vez que $PS2se evalúe hasta que $PS1una vez más se restablezca. Me gusta esto:
PS2='$((PS2c=PS2c+1)) > '
Entonces ahora puedo:
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
Funciona igual en basho 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
Como dije anteriormente, el problema principal es que debes considerar dónde haces tu cálculo. No obtiene el estado en el shell principal, por lo que no calcula allí. Obtiene el estado en la subshell, así que ahí es donde calcula. Pero haces la definición en el shell principal.
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.