
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 /tmpper 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 %cstringa, 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 $PS1viene valutato, analizza e stampa $PWDper aggiungere al prompt. Ma non mi piace l'intero $PWDaffollamento 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 $PWDe il modo più affidabile per farlo è con $IFSsplit 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 $PWDsu /simboli. Uso anche l'espansione dei parametri per assegnare a $lasttutto 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 $lastsarà ancora uguale tutto $PWDe $1sarà vuota. Questo conta. Mi spoglio anche $lastdalla fine della coda $PWDprima di assegnarlo a $@.
printf "${1+%c/}" "$@"
Quindi qui - fintanto che ${1+is set}siamo printfi primi a %cbattere 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 $PWDma quello in alto. È importante però rendersi conto che ciò accade solo se $1viene 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 $PS2condizionale. 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 \bspazi 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 dashe shproprio come in bashe 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 $PS2viene valutato fino a $PS1quando 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 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
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.