Como salvar o histórico do terminal em um arquivo a partir de um arquivo bash?

7

Estou tentando criar um script bash que salvará o histórico do terminal em um arquivo chamado hist.txt. O uso history > hist.txtnão parece funcionar no script bash, mas funciona bem quando executado na linha de comando.

Qualquer orientação é muito apreciada.

Obrigado Judy

Judy
fonte
3
Sua pergunta é um pouco confusa. O que você quer dizer com "não parece funcionar no arquivo bash, mas funciona bem quando executado na linha de comando"? Você quer dizer que está tentando salvar seu histórico de comandos em um script bash que está sendo executado? Como você deseja salvar quais comandos foram executados pelo script? O script em si é uma história neste caso.
Stephen Stephen
6
Ou você deseja exibir o histórico do bash de um usuário específico? Você pode apenas ler o ~/.bash_historyarquivo do usuário .
Arronical
1
@ Observe que isso só funcionará se o usuário estiver usando o Bash como seu shell, o que nem sempre é o caso.
1
@ p0llard Obviamente, entrei no pressuposto de que, como estava em um script do Bash, seria o Bash como o shell do usuário, mas pode não ser o caso, como você disse. Bons detalhes e antecedentes em sua resposta.
Arronical

Respostas:

11

Resposta curta

Execute o script com sourceou .:

source ./script_name.sh

ou

. ./script_name.sh

Este último é um pouco mais compatível entre diferentes conchas.

Resposta longa

Esta pergunta destaca um ponto importante, que é que os scripts de shell são executados em seu próprio contexto. Para ver o que isso significa, considere o seguinte script de shell:

#!/bin/bash

cd /
ls

Se você executar isso, obterá uma saída semelhante a esta:

bin  boot  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

Mas você notará que, depois de executar o script, você ainda está no diretório em que estava antes de executá-lo: o cd /interior do script não afetou sua sessão - apenas afetou o contexto em que o script estava sendo executado, o que é criado para a execução do script e destruído quando ele retorna.

O sourcecomando 'lerá e executará comandos do argumento do nome do arquivo no contexto atual do shell'; portanto, qualquer comando como cdesse dentro afetará sua sessão atual. Se você executasse o script acima, passando-o para sourcevocê, descobriria que acabaria dentro do diretório raiz após a execução .

Nesse caso, o problema é que o historycomando fornece o histórico do contexto atual do shell; o contexto do shell em que seu script é executado sem o uso sourcenão tem histórico; portanto, ele não grava nada no arquivo de saída. Se você o usar, sourceele será executado no contexto correto e funcionará conforme o esperado.

NB: sourceé built-in, não um programa de uma concha per se - em Bash, sourceé sinônimo de ., mas em algumas conchas única .vai funcionar - Eu usei sourcenesta resposta porque é mais fácil de ler do que ., mas para o máximo de compatibilidade, .deve ser usado.


fonte
Leitura muito interessante. Eu sempre me perguntei sobre 'falta' de comandos de história, agora eu sei o porquê. Obrigado!
Tico
10

Antes de tudo, observe que seu histórico já está em um arquivo. Se você estiver executando o bash, seu nome geralmente é ~/.bash_history. Mais especificamente, é como você definiu a variável HISTFILE. Se você deseja copiá-lo para outro arquivo, basta executarcat "$HISTFILE" > hist.txt

Agora, por que o historycomando não funciona em um script shell bash, é porque os scripts são executados em um shell filho não interativo da sua sessão atual do shell. Os shells filhos não herdam todo o ambiente do pai (portanto, nem todas as variáveis ​​definidas), apenas as variáveis ​​que foram exportadas. Para ilustrar, o script abaixo fará eco do valor da variável $var:

#!/bin/bash
echo "$var"

Agora, defina $varalgo e execute o script:

$ var="foo"
$ foo.sh
VAR: 

Em seguida, exporte a variável primeiro:

$ var="foo"
$ export var
$ foo.sh
VAR: foo

Como você pode ver, quando a variável foi exportada, ela está disponível para shells filhos.

Como mencionei antes, o histórico é armazenado no arquivo apontado pela variável $HISTFILENAME. Como isso não é exportado por padrão, ele não é definido ao executar um script:

$ cat foo.sh
#!/bin/bash
echo "HISTFILE: $HISTFILE"
$ ./foo.sh
HISTFILE:
$ echo $HISTFILE
/home/terdon/.bash_history

Como você pode ver no exemplo acima, a variável HISTFILEé definida na minha sessão normal do shell, mas fica vazia ao executar o script.

Portanto, para obter o histórico, você tem algumas opções:

  1. O HISTFILEvalor padrão é $HOME/.bash_history. Se você não mudou isso, basta executar este comando no seu script:

    cat "$HOME/.bash_history" > history
  2. Você pode passar a $HISTFILEvariável para o seu script e catque:

    #!/bin/bash
    cat "$1" > history

    Salve o acima foo.she execute assim:

    ./foo.sh "$HISTORY"
  3. Verifique se a variável é exportada. Adicione esta linha aos seus arquivos ~/.bash_profile(se existir) ou ~/.profile(se ~/.bash_profilenão existir):

    export HISTFILE

    Em seguida, efetue logout e logon novamente e você poderá executar a history > hist.txtpartir de um script conforme o esperado. Isso ocorre porque export VARsignifica "disponibilizar o $ VAR para conchas filho". Em termos práticos, isso significa que o valor de HISTFILEserá herdado pelo shell não interativo que você usa para executar seu script.

    Agora, enquanto o HISTFILEserá definido, ele não foi lido pelo shell executando o script. Portanto, para que funcione, você precisa history -rprimeiro ler . O script inteiro ficaria assim:

    $!/bin/bash
    history -r
    history > hist.txt

    Como alternativa, basta exportá-lo manualmente antes de executar o script:

    $ export HISTFILE

    Mas você ainda precisará history -rno script.

  4. Você pode sourcesugerir a resposta de @ p0llard .

Terdon
fonte