Per ottenere lo stesso risultato che noti nella tua domanda, tutto ciò che serve è questo:
PS1='${PS2c##*[$((PS2c=0))-9]}- > '
PS2='$((PS2c=PS2c+1)) > '
Non è necessario contorcersi. Queste due linee faranno tutto in qualsiasi shell che finge di qualcosa di simile alla compatibilità POSIX.
- > cat <<HD
1 > line 1
2 > line $((PS2c-1))
3 > HD
line 1
line 2
- > echo $PS2c
0
Ma questo mi è piaciuto. E volevo dimostrare i fondamenti di ciò che rende questo lavoro un po 'migliore. Quindi l'ho modificato un po '. L'ho bloccato /tmp
per ora, ma penso che lo terrò anche per me stesso. È qui:
cat /tmp/prompt
SCRITTTO PRONTO:
ps1() { IFS=/
set -- ${PWD%"${last=${PWD##/*/}}"}
printf "${1+%c/}" "$@"
printf "$last > "
}
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
PS2='$((PS2c=PS2c+1)) > '
Nota: dopo aver appreso di yash , l'ho costruito ieri. Per qualsiasi motivo, non stampa il primo byte di ogni argomento con la %c
stringa, sebbene i documenti fossero specifici sulle estensioni di caratteri generici per quel formato e quindi potrebbe essere correlato, ma funziona bene con%.1s
Questo è tutto. Ci sono due cose principali che succedono lassù. E questo è come appare:
/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
Ogni volta che $PS1
viene valutato, analizza e stampa $PWD
per aggiungere al prompt. Ma non mi piace l'intero $PWD
affollamento del mio schermo, quindi voglio solo la prima lettera di ogni briciola di pane nel percorso corrente fino alla directory corrente, che mi piacerebbe vedere per intero. Come questo:
/h/mikeserv > cd /etc
/etc > cd /usr/share/man/man3
/u/s/m/man3 > cd /
/ > cd ~
/h/mikeserv >
Ci sono alcuni passaggi qui:
IFS=/
dovremo dividere l'attuale $PWD
e il modo più affidabile per farlo è con $IFS
split on /
. Non c'è bisogno di preoccuparsene in seguito - tutte le divisioni da qui in avanti saranno definite $@
dall'array di parametri posizionali della shell nel comando successivo come:
set -- ${PWD%"${last=${PWD##/*/}}"}
Quindi questo è un po 'complicato, ma la cosa principale è che stiamo splitting $PWD
su /
simboli. Uso anche l'espansione dei parametri per assegnare a $last
tutto dopo che si è verificato un valore tra la /
barra più a sinistra e quella più a destra . In questo modo so che se io sono solo a /
ed avere un solo /
allora $last
sarà ancora uguale tutto $PWD
e $1
sarà vuota. Questo conta. Mi spoglio anche $last
dalla fine della coda $PWD
prima di assegnarlo a $@
.
printf "${1+%c/}" "$@"
Quindi qui - fintanto che ${1+is set}
siamo printf
i primi a %c
battere gli argomenti di ogni nostra shell - che abbiamo appena impostato su ciascuna directory nella nostra attuale $PWD
- meno la directory superiore - divisi /
. Quindi essenzialmente stiamo solo stampando il primo carattere di ogni directory $PWD
ma quello in alto. È importante però rendersi conto che ciò accade solo se $1
viene impostato affatto, che non accadrà alla radice /
o a uno rimosso da /
come in /etc
.
printf "$last > "
$last
è la variabile che ho appena assegnato alla nostra directory principale. Quindi ora questa è la nostra directory principale. Stampa indipendentemente dall'ultima affermazione. E ci vuole un po 'di pulito >
per una buona misura.
MA CHE COSA RIGUARDA L'INCREMENTO?
E poi c'è la questione del $PS2
condizionale. Ho mostrato in precedenza come si può fare ciò che è ancora possibile trovare di seguito - questo è fondamentalmente un problema di portata. Ma c'è un po 'di più a meno che tu non voglia iniziare a fare un sacco di printf \b
spazi aperti e quindi provare a bilanciare il loro conteggio dei personaggi ... ugh. Quindi faccio questo:
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
Ancora una volta, ${parameter##expansion}
salva la giornata. È un po 'strano qui - in realtà impostiamo la variabile mentre la rimuoviamo da sola. Usiamo il suo nuovo valore - set mid-strip - come il glob da cui rimuoviamo. Vedi? Ci ##*
spogliamo tutti dal capo della nostra variabile di incremento per l'ultimo carattere che può essere qualsiasi cosa, da [$((PS2c=0))-9]
. In questo modo siamo garantiti di non produrre il valore, eppure lo assegniamo ancora. È abbastanza bello - non l'ho mai fatto prima. Ma POSIX ci garantisce anche che questo è il modo più portatile per farlo.
Ed è grazie a POSIX specificato ${parameter} $((expansion))
che mantiene queste definizioni nella shell corrente senza richiedere che le impostiamo in una subshell separata, indipendentemente da dove le valutiamo. Ed è per questo che funziona in dash
e sh
proprio come in bash
e zsh
. Non usiamo escape dipendenti dalla shell / terminali e lasciamo che le variabili si testino da sole. Questo è ciò che rende veloce il codice portatile .
Il resto è abbastanza semplice: basta incrementare il nostro contatore per ogni volta che $PS2
viene valutato fino a $PS1
quando non lo si ripristina nuovamente. Come questo:
PS2='$((PS2c=PS2c+1)) > '
Quindi ora posso:
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
Funziona allo stesso modo in bash
o 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
Come ho detto sopra, il problema principale è che devi considerare dove fai il tuo calcolo. Non si ottiene lo stato nella shell padre, quindi non si calcola lì. Ottieni lo stato nella subshell - quindi è lì che calcoli. Ma fai la definizione nella shell genitore.
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
.