Com o GNU awk
:
tail -fn+1 ~/.bash_history | awk '
/^#/{printf "%-4d [%s] ", ++n, strftime("%F %T", substr($0, 2)); next}; 1'
Eu uso um simples alias para ativar o "rastreamento" de comandos em uma ou várias janelas de terminal:
alias trackmi='export PROMPT_COMMAND="history -a; $PROMPT_COMMAND"'
Então eu só tail -f
meu arquivo .bash_history em outro terminal no espaço de trabalho para obter feedback imediato. Acabei de ativar o histórico ilimitado e atualizei meu formato de histórico ( export HISTTIMEFORMAT="[%F %T] "
) em .bashrc . É claro que o comando history
exibe os registros de data e hora. Mas o formato do arquivo de histórico é:
#1401234303
alias
#1401234486
cat ../.bashrc
Como posso ter o tempo do Unix convertido e todo o comando exibido em uma única linha como no comando history
, incluindo numeração:
578 [2014-05-27 19:45:03] alias
579 [2014-05-27 19:48:06] cat ../.bashrc
... e siga isso. Ou encontrar uma maneira de gerar continuamente a saída do comando history
para o terminal?
Aqui está o produto final em ação em um xterm de tela dividida, basicamente de padrões de shell, para trabalhar em apenas alguns comandos:
Umamaneiramaisdifícildefazerissodoqueédemonstradonacapturadetelapodeserassim:
PS1='$({date;fc-l-0;}>${TGT_PTY})'$PS1
Onde${TGT_PTY}
seriaoquevocêreceberdocomandotty
quandoestiverexecutandoumshellinterativonatelaondedesejasuasaída.Ou,naverdade,vocêpoderiausarqualquerarquivogravável,poiséessencialmenteapenasumalvoparaoredirecionamentodearquivos.
Euusoasintaxeptyparapseudo-terminalporqueestouassumindoqueéumxtermdealgumtipo,masvocêpodefacilmentededicarumvt-eseustreamedohistóricoésempreapenasumacombinaçãode%CTRL-ALT-Fn
.Sefosseeu,eupoderiacombinarasduasnoçõesetorná-loumasessãoscreen
outmux
emumvtdedicado...Maseudiscordo.
Emumamáquinarecém-inicializada,sourecebidocomoprompttípico/bin/login
emumconsoletípicodoLinuxgetty
.EupressionoCTRL-ALT-F2
paraacessarumconsolekmscon
menostípicoquesecomportamuitomaiscomoxterm
doquetty
.Euinsiroocomandotty
ereceboemresposta/dev/pts/0
.
Geralmentextermsmultiplexamumúnicoterminalemmúltiplosusandopseudo-terminais-entãosevocêfizessealgosimilarnoX11trocandoentreasabasoujanelasdoterminal,vocêprovavelmentereceberiaumasaídacomo/dev/pts/[0-9]*
também.MasosconsolesdeterminalvirtuaisacessadoscomcombinaçõesdeteclasCTRL-ALT-Fn
sãodispositivosdeterminaltrue(er)e,portanto,recebemsuaprópriadesignação/dev/tty[0-9]*
.
Éporissoquedepoisdeefetuarloginnoconsole2quandodigitotty
noprompt,arespostaé/dev/pts/0
,masquandoeufaçoomesmonoconsole1,asaídaé/dev/tty1
.Dequalquerforma,devoltaaoconsole2eufaço:
bashPS1='$({date;fc-l-0;}>/dev/tty1)'$PS1
Nãoháefeitodiscernível.Eucontinuodigitandomaisalgunscomandosedepoismudoparaoconsole1pressionandoCTRL-ALT-F1
novamente.Eláeuencontroentradasrepetidasqueparecemcom<date_time>\n<hist#>\t<hist_cmd_string>
paracadacomandoqueeudigiteinoconsole2.
Noentanto,impedindoagravaçãodiretaemumdispositivodeterminal,outraopçãopoderiaseralgocomo:
TGT_PTY=mkfifo${TGT_PTY:=/tmp/shell.history.pipe}{echo'OPENEDON:'date}>${TGT_PTY}
Eentãotalvez...
less+F${TGT_PTY}
Ocomandopromptbrutonãoatendeàssuasespecificações-nenhumastringdeformatoparadate
enenhumaopçãodeformataçãoparafc
-,masseumecanismonãoexigemuito:todavezqueseupromptrenderizaroúltimocomandohistóricoeadataehoraatuaissãogravadasnoarquivo${TGT_PTY}
quevocêespecificar.Étãosimplesassim.
Assistireimprimirohistóricodoshelléoobjetivoprincipaldefc
.Éumshellembutido,mesmoquedate
nãoseja.Emzsh
fc
podefornecertodosostiposdeopçõesdeformataçãoextravagantes,váriasdasquaisseaplicamacarimbosdedata/hora.E,claro,comovocêobservouacima,bash
'history
podefazeromesmo.
Nointeressedaproduçãomaislimpa,vocêpodeusarumatécnicaqueexpliqueimelhor
Aqui está um meio portátil de formatação de acordo 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 últimas atualizações para que você não escreva o mesmo comando history duas vezes - por exemplo, apenas pressionando enter. Há um pouco de discussão necessária para obter a variável incrementada no shell atual, de modo que ela retenha seu valor mesmo que a função seja chamada em um subshell - o que é, novamente, melhor explicado no link .
Sua saída parece com <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 builtins de 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 o comando bash
' history
, você pode definir a função _HIST
desta maneira:
_HIST() { [ -z ${_LH#$1} ] ||
HISTTIMEFORMAT="[%F %T]<tab>" \
history 1 >${TGT_PTY}
printf "(_LH=$1)-$1"
}
A saída de qualquer método também se parece com: <hist#>\t[%F %T]\t<hist_cmd>\n
, embora o método history
inclua alguns espaços em branco iniciais. Ainda assim, acredito que os timestamps do método history
serão mais precisos, pois não acredito que precisem esperar que o comando referenciado seja concluído antes de adquirir seu selo.
Você pode evitar o rastreamento de qualquer estado em ambos os casos se, de alguma forma, você filtrar o fluxo com uniq
, como faria com mkfifo
, como mencionei antes.
Mas fazê-lo no prompt desse jeito significa que ele sempre é atualizado 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 com tail
, mas definir
HISTFILE=${TGT_PTY}
Sinta-se à vontade para jogar com a formatação, mas isso (eu acredito) faz o que você está pedindo ... salve em algum lugar no seu PATH, torne executável e aproveite:
#!/bin/bash
count=$( echo "scale=0 ; $(cat ~/.bash_history | wc -l ) / 2" | bc -l )
tail -f ~/.bash_history | awk -v c=$count '{if($1 ~/^#/){gsub(/#/, "", $1);printf "%s\t", c; "date \"+%F %T\" --date @" $1 | getline stamp; printf "[%s]\t",stamp;c++}else{print $0}}'
Tenho certeza de que pode ser otimizado, mas você tem a ideia.
Breve explicação: como o ~ / .bash_history não controla a contagem, primeiro determinamos o número de entradas. Então, um pouco de magia awk para obter a formatação correta e acompanhar o número de entradas.