Aquí está el producto final en acción en un xterm de pantalla dividida, desde los valores predeterminados de shell hasta el trabajo en solo un par de comandos:

Una forma más dura de hacer esto que la que se muestra en la captura de pantalla podría verse así:
PS1='$( { date ; fc -l -0 ; } >${TGT_PTY} )'$PS1
¿Dónde ${TGT_PTY}estaría lo que obtiene del ttycomando cuando realmente ejecuta un shell interactivo en la pantalla donde desea su salida? O, realmente, podría usar cualquier archivo que se pueda escribir, ya que esencialmente es solo un objetivo para la redirección de archivos.
Utilizo la sintaxis pty para pseudo-terminal porque supongo que es un xterm de algún tipo, pero podría dedicar un vt con la misma facilidad, y su historial transmitido siempre está a solo una CTRL-ALT-Fncombinación de teclas. Si fuera yo podría combinar las dos nociones y convertirla en una screeno tmuxsesión en un vt dedicada ... Pero estoy divagando.
En una máquina recién iniciada, recibo el típico /bin/loginaviso en una gettyconsola típica de Linux . Presiono CTRL-ALT-F2para acceder a una kmsconconsola menos típica que se comporta mucho más como un xtermque a tty. Entro en el comando ttyy recibo en respuesta /dev/pts/0.
En general, xterms multiplexa un dispositivo de terminal único en múltiples usando pseudo terminales , por lo que si hiciera algo similar en X11 al cambiar entre pestañas de terminal o ventanas, probablemente también recibiría la salida /dev/pts/[0-9]*. Pero las consolas de terminal virtual a las que se accede con CTRL-ALT-Fncombinaciones de teclas son dispositivos de terminal verdaderos (er) y, por lo tanto, reciben su propia /dev/tty[0-9]*designación.
Es por eso que después de iniciar sesión en la consola 2 cuando escribo ttyen el indicador, la respuesta es /dev/pts/0pero cuando hago lo mismo en la consola 1, la salida es /dev/tty1. En cualquier caso, de vuelta en la consola 2, entonces hago:
bash
PS1='$( { date ; fc -l -0 ; } >/dev/tty1 )'$PS1
No hay efecto discernible. Continúo escribiendo algunos comandos más y luego cambio a la consola 1 presionando CTRL-ALT-F1nuevamente. Y allí encuentro entradas repetidas que se parecen <date_time>\n<hist#>\t<hist_cmd_string>a cada comando que escribí en la consola 2.
Sin embargo, salvo escribir directamente en un dispositivo terminal, otra opción podría ser algo como:
TGT_PTY=
mkfifo ${TGT_PTY:=/tmp/shell.history.pipe}
{ echo 'OPENED ON:'
date
} >${TGT_PTY}
Y entonces tal vez ...
less +F ${TGT_PTY}
El comando de solicitud aproximada no cumple con sus especificaciones, sin cadenas de dateformato ni opciones de formato para fcninguna de ellas, pero su mecanismo no requiere mucho: cada vez que su solicitud representa el último comando del historial y la fecha y hora actuales se escriben en El ${TGT_PTY}archivo que especifique. Es tan simple como eso.
Mirar e imprimir el historial de shell es fcel propósito principal. Es un shell incorporado, incluso si dateno lo es. En zsh fcpuede proporcionar todo tipo de opciones de formato sofisticadas, varias de las cuales se aplican a las marcas de tiempo. Y, por supuesto, como observas más arriba, bashlos s historypueden hacer lo mismo.
En aras de una salida más limpia, puede usar una técnica que he explicado mejor aquí para establecer una variable de seguimiento persistente en el shell actual a pesar de tener que rastrearlo y procesarlo en subcapas dentro de la secuencia de solicitud.
Aquí hay un medio portátil de formatear según sus especificaciones:
_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 el contador last_history$_LH que solo rastrea las últimas actualizaciones para que no escriba el mismo comando de historial dos veces, por ejemplo, solo por presionar enter. Hay un poco de discusión necesaria para que la variable se incremente en el shell actual para que conserve su valor a pesar de que la función se llama en un subshell, que, una vez más, se explica mejor en el enlace .
Su salida se ve como <hist#>\t[%F %T]\t<hist_cmd>\n
Pero esa es solo la versión totalmente portátil. Con bashesto se puede hacer con menos y mediante la implementación solo de los componentes integrados de shell, lo que probablemente sea deseable cuando se considera que este es un comando que se ejecutará cada vez que presione [ENTER]. Aquí hay dos formas:
_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
Alternativamente, utilizando bashel historycomando 's , puede definir la _HISTfunción de esta manera:
_HIST() { [ -z ${_LH#$1} ] ||
HISTTIMEFORMAT="[%F %T]<tab>" \
history 1 >${TGT_PTY}
printf "(_LH=$1)-$1"
}
La salida para cualquiera de los métodos también se ve así: <hist#>\t[%F %T]\t<hist_cmd>\naunque el historymétodo incluye algunos espacios en blanco iniciales. Aún así, creo que las historymarcas de tiempo del método serán más precisas ya que no creo que tengan que esperar a que se complete el comando referenciado antes de adquirir su sello.
Puede evitar el seguimiento de cualquier estado en ambos casos si solo de alguna manera filtra la transmisión uniq, como podría hacer con mkfifolo que mencioné antes.
Pero hacerlo en el indicador de esta manera significa que siempre se actualiza solo tan pronto como sea necesario por la simple acción de actualizar el indicador. Es simple.
También puede hacer algo similar a lo que está haciendo, tailpero más bien establecer
HISTFILE=${TGT_PTY}
fn+1para comparar. ¡Gracias!