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 tty
comando 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-Fn
combinación de teclas. Si fuera yo podría combinar las dos nociones y convertirla en una screen
o tmux
sesión en un vt dedicada ... Pero estoy divagando.
En una máquina recién iniciada, recibo el típico /bin/login
aviso en una getty
consola típica de Linux . Presiono CTRL-ALT-F2
para acceder a una kmscon
consola menos típica que se comporta mucho más como un xterm
que a tty
. Entro en el comando tty
y 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-Fn
combinaciones 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 tty
en el indicador, la respuesta es /dev/pts/0
pero 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-F1
nuevamente. 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 date
formato ni opciones de formato para fc
ninguna 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 fc
el propósito principal. Es un shell incorporado, incluso si date
no lo es. En zsh
fc
puede 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, bash
los s history
pueden 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 bash
esto 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 bash
el history
comando 's , puede definir la _HIST
funció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>\n
aunque el history
método incluye algunos espacios en blanco iniciales. Aún así, creo que las history
marcas 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 mkfifo
lo 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, tail
pero más bien establecer
HISTFILE=${TGT_PTY}
fn+1
para comparar. ¡Gracias!