Ecco il prodotto finale in azione su un xterm a schermo diviso dalle impostazioni predefinite della shell al funzionamento con solo un paio di comandi:
Un modo più semplice per farlo rispetto a quanto mostrato nello screenshot potrebbe apparire così:
PS1='$( { date ; fc -l -0 ; } >${TGT_PTY} )'$PS1
Dove ${TGT_PTY}
sarebbe qualsiasi cosa tu ottenga dal tty
comando quando effettivamente esegui una shell interattiva sullo schermo in cui vuoi il tuo output. O, davvero, potresti usare qualsiasi file scrivibile in quanto è essenzialmente solo una destinazione per il reindirizzamento dei file.
Uso la sintassi pty per lo pseudo-terminale perché suppongo che sia un xterm di qualche tipo, ma potresti dedicare facilmente un vt - e la tua cronologia in streaming è sempre solo una CTRL-ALT-Fn
combinazione chiave. Se fossi in me potrei combinare le due nozioni e renderle una screen
o tmux
sessione su un vt dedicato ... Ma sto divagando.
Su una macchina appena avviata sono accolto con il tipico /bin/login
prompt su una tipica getty
console Linux . Premo CTRL-ALT-F2
per accedere a una kmscon
console meno tipica che si comporta in modo molto più simile a una xterm
che a tty
. Inserisco il comando tty
e ricevo in risposta /dev/pts/0
.
Generalmente xterm multiplexa un singolo dispositivo terminale in multiplo usando pseudo-terminali - quindi se dovessi fare una cosa simile in X11 passando da una scheda terminale a un'altra finestra, probabilmente riceveresti anche l'output /dev/pts/[0-9]*
. Ma le console terminali virtuali a cui si accede con CTRL-ALT-Fn
combinazioni di tasti sono veri e propri dispositivi terminali e quindi ricevono la loro /dev/tty[0-9]*
designazione.
Questo è il motivo per cui dopo aver effettuato l'accesso alla console 2 quando digito tty
al prompt la risposta è /dev/pts/0
ma quando faccio lo stesso sulla console 1 l'output è /dev/tty1
. In ogni caso, tornando sulla console 2, faccio quindi:
bash
PS1='$( { date ; fc -l -0 ; } >/dev/tty1 )'$PS1
Non c'è alcun effetto riconoscibile. Continuo a digitare qualche altro comando e poi passo alla console 1 premendo di CTRL-ALT-F1
nuovo. E lì trovo voci ripetute che assomigliano <date_time>\n<hist#>\t<hist_cmd_string>
a ogni comando che ho digitato sulla console 2.
Escludendo la scrittura diretta su un dispositivo terminale, tuttavia, un'altra opzione potrebbe essere simile a:
TGT_PTY=
mkfifo ${TGT_PTY:=/tmp/shell.history.pipe}
{ echo 'OPENED ON:'
date
} >${TGT_PTY}
E poi forse ...
less +F ${TGT_PTY}
Il comando del prompt approssimativo non soddisfa le tue specifiche - nessuna stringa di formato per date
e nessuna opzione di formattazione per fc
entrambi - ma il suo meccanismo non richiede molto: ogni volta che il tuo prompt esegue il rendering dell'ultimo comando della cronologia e la data e l'ora correnti vengono scritte in il ${TGT_PTY}
file specificato. E 'così semplice.
Guardare e stampare la cronologia delle shell è fc
lo scopo principale. È una shell integrata, anche se date
non lo è. In zsh
fc
può fornire tutti i tipi di opzioni di formattazione fantasiose, molte delle quali si applicano ai timestamp. E naturalmente, come si nota in precedenza, bash
's history
può fare lo stesso.
Nell'interesse di un output più pulito, è possibile utilizzare una tecnica che ho spiegato meglio qui per impostare una variabile di tracciamento persistente nella shell corrente nonostante sia necessario rintracciarla ed elaborarla in subshells all'interno della sequenza di prompt.
Ecco un mezzo portatile per formattare secondo le tue specifiche:
_HIST() { [ -z ${_LH#$1} ] ||
{ date "+${1}%t[%F %T]"
fc -nl -0
} >${TGT_PTY}
printf "(_LH=$1)-$1"
}
: "${_LH=0}"
PS1='${_LH##*[$(($(_HIST \!)))-9]}'$PS1
Implemento il contatore last_history$_LH
che tiene traccia degli ultimi aggiornamenti in modo da non scrivere due volte lo stesso comando di cronologia, ad esempio semplicemente premendo Invio. È necessario un po 'di wrangling per ottenere l'incremento della variabile nella shell corrente in modo che mantenga il suo valore anche se la funzione è chiamata in una subshell - che è, ancora una volta, meglio spiegata nel collegamento .
Sembra che il suo output <hist#>\t[%F %T]\t<hist_cmd>\n
Ma questa è solo la versione completamente portatile. Con bash
esso può essere fatto con meno e implementando solo i builtin della shell - il che è probabilmente auspicabile se si considera che questo è un comando che verrà eseguito ogni volta che si preme [ENTER]
. Ecco due modi:
_HIST() { [ -z ${_LH#$1} ] || {
printf "${1}\t[%(%F %T)T]"
fc -nl -0
} >${TGT_PTY}
printf "(_LH=$1)-$1"
}
PROMPT_COMMAND=': ${_LH=0};'$PROMPT_COMMAND
PS1='${_LH##*[$(($(_HIST \!)))-9]}'$PS1
In alternativa, usando bash
il history
comando ', puoi definire la _HIST
funzione in questo modo:
_HIST() { [ -z ${_LH#$1} ] ||
HISTTIMEFORMAT="[%F %T]<tab>" \
history 1 >${TGT_PTY}
printf "(_LH=$1)-$1"
}
Anche l'output per entrambi i metodi è simile: <hist#>\t[%F %T]\t<hist_cmd>\n
sebbene il history
metodo includa alcuni spazi bianchi iniziali. Tuttavia, credo che i history
timestamp del metodo saranno più precisi in quanto non penso che dovrebbero attendere il completamento del comando di riferimento prima di acquisire il loro timbro.
Puoi evitare di tracciare qualsiasi stato in entrambi i casi se solo in qualche modo filtri lo stream con uniq
, come potresti fare con mkfifo
come ho già detto prima.
Ma farlo nel prompt in questo modo significa che è sempre aggiornato solo non appena è necessario semplicemente aggiornando il prompt. È semplice.
Potresti anche fare qualcosa di simile a quello che stai facendo tail
ma piuttosto impostare
HISTFILE=${TGT_PTY}
fn+1
per confrontare! Grazie!