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 ttycomando 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-Fncombinazione chiave. Se fossi in me potrei combinare le due nozioni e renderle una screeno tmuxsessione su un vt dedicato ... Ma sto divagando.
Su una macchina appena avviata sono accolto con il tipico /bin/loginprompt su una tipica gettyconsole Linux . Premo CTRL-ALT-F2per accedere a una kmsconconsole meno tipica che si comporta in modo molto più simile a una xtermche a tty. Inserisco il comando ttye 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-Fncombinazioni 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 ttyal prompt la risposta è /dev/pts/0ma 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-F1nuovo. 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 datee nessuna opzione di formattazione per fcentrambi - 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 è fclo scopo principale. È una shell integrata, anche se datenon lo è. In zsh fcpuò 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 historypuò 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 bashesso 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 bashil historycomando ', puoi definire la _HISTfunzione 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>\nsebbene il historymetodo includa alcuni spazi bianchi iniziali. Tuttavia, credo che i historytimestamp 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 mkfifocome 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 tailma piuttosto impostare
HISTFILE=${TGT_PTY}
fn+1per confrontare! Grazie!