Aqui está o produto final em ação em um xterm de tela dividida, dos padrões basicamente do shell ao trabalho em apenas alguns comandos:
Uma maneira mais difícil de fazer isso do que é demonstrado na captura de tela pode ser assim:
PS1='$( { date ; fc -l -0 ; } >${TGT_PTY} )'$PS1
Onde ${TGT_PTY}
estaria o que você obtém do tty
comando ao executar um shell interativo na tela em que deseja sua saída. Ou, realmente, você pode usar qualquer arquivo gravável, pois é essencialmente apenas um alvo para o redirecionamento de arquivos.
Eu uso a sintaxe pty para pseudo-terminal, porque estou assumindo que é um xterm de algum tipo, mas você pode dedicar um vt com a mesma facilidade - e seu histórico transmitido é sempre apenas uma CTRL-ALT-Fn
combinação de teclas. Se fosse comigo eu poderia combinar as duas noções e torná-lo um screen
ou tmux
sessão em um vt dedicado ... Mas eu discordo.
Em uma máquina recém-inicializada, sou recebido com o /bin/login
prompt típico em um getty
console Linux típico . Pressiono CTRL-ALT-F2
para acessar um kmscon
console menos típico que se comporta muito mais como um xterm
que com um tty
. Entro no comando tty
e recebo em resposta /dev/pts/0
.
Geralmente, os xterms multiplexam um único dispositivo de terminal em vários usando pseudo-terminais - portanto, se você fizesse algo semelhante no X11 alternando entre as guias ou janelas do terminal, provavelmente também receberia saída /dev/pts/[0-9]*
. Mas os consoles de terminais virtuais acessados com CTRL-ALT-Fn
combinações de teclas são verdadeiros dispositivos de terminal e, portanto, recebem sua própria /dev/tty[0-9]*
designação.
É por isso que, depois de entrar no console 2, quando digito tty
no prompt, a resposta é, /dev/pts/0
mas quando faço o mesmo no console 1, a saída é /dev/tty1
. De qualquer forma, de volta ao console 2, faço:
bash
PS1='$( { date ; fc -l -0 ; } >/dev/tty1 )'$PS1
Não há efeito discernível. Continuo digitando mais alguns comandos e depois mudo para o console 1 pressionando CTRL-ALT-F1
novamente. E lá encontro entradas repetidas que se parecem com <date_time>\n<hist#>\t<hist_cmd_string>
todos os comandos que digitei no console 2.
Com exceção da gravação direta em um dispositivo terminal, outra opção poderia ser algo como:
TGT_PTY=
mkfifo ${TGT_PTY:=/tmp/shell.history.pipe}
{ echo 'OPENED ON:'
date
} >${TGT_PTY}
E então talvez ...
less +F ${TGT_PTY}
O comando rough prompt não atende às suas especificações - nenhuma string de date
formatação para e nenhuma opção de formatação para fc
elas - mas seu mecanismo não exige muito: toda vez que seu prompt renderiza o último comando do histórico e a data e hora atuais são gravadas em o ${TGT_PTY}
arquivo que você especificar. É simples assim.
Observar e imprimir o histórico do shell é fc
o objetivo principal do. É um shell embutido, mesmo que date
não seja. O In zsh
fc
pode fornecer todos os tipos de opções de formatação sofisticadas, várias das quais se aplicam a carimbos de data e hora. E é claro, como você notou acima, bash
o history
pode fazer o mesmo.
No interesse de uma saída mais limpa, você pode usar uma técnica que expliquei melhor aqui para definir uma variável de rastreamento persistente no shell atual, apesar de ter que rastreá-lo e processá-lo em subshells na sequência de prompt.
Aqui está um meio portátil de formatar com suas especificações:
_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
Eu implemento o contador last_history$_LH
que apenas rastreia as atualizações mais recentes para que você não escreva o mesmo comando de histórico duas vezes - por exemplo, apenas pressionando enter. Há um pouco de disputa necessária para incrementar a variável no shell atual, para que ela retenha seu valor mesmo que a função seja chamada em um subshell - o que é novamente explicado melhor no link .
Sua saída parece <hist#>\t[%F %T]\t<hist_cmd>\n
Mas essa é apenas a versão totalmente portátil. Com bash
isso, pode ser feito com menos e implementando apenas os recursos internos do shell - o que provavelmente é desejável quando você considera que este é um comando que será executado toda vez que você pressionar [ENTER]
. Aqui estão duas maneiras:
_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
Como alternativa, usando bash
o history
comando 's , você pode definir a _HIST
função desta maneira:
_HIST() { [ -z ${_LH#$1} ] ||
HISTTIMEFORMAT="[%F %T]<tab>" \
history 1 >${TGT_PTY}
printf "(_LH=$1)-$1"
}
A saída para qualquer método também se parece com: <hist#>\t[%F %T]\t<hist_cmd>\n
embora o history
método inclua alguns espaços em branco à esquerda. Ainda assim, acredito que os history
carimbos de data e hora do método serão mais precisos, pois não acho que precisariam esperar o comando referenciado ser concluído antes de adquirir o carimbo.
É possível evitar o rastreamento de qualquer estado nos dois casos, se você filtrar o fluxo de alguma forma uniq
- como você pode fazer mkfifo
como mencionei antes.
Mas fazê-lo no prompt como este significa que ele sempre é atualizado apenas assim que necessário, apenas pela simples ação de atualizar o prompt. É simples.
Você também pode fazer algo semelhante ao que está fazendo, tail
mas definir
HISTFILE=${TGT_PTY}
fn+1
para comparar! Obrigado!