web-dev-qa-db-fra.com

Comment enregistrer l'historique du terminal dans un fichier à partir d'un fichier bash?

J'essaie de créer un script bash qui enregistrera l'historique du terminal dans un fichier appelé hist.txt. Utiliser history > hist.txt ne semble pas fonctionner dans le script bash, mais fonctionne correctement lorsqu'il est exécuté dans la ligne de commande.

Toute orientation est grandement appréciée.

Merci Judy

8
Judy

Réponse courte

Exécutez le script avec source ou .:

source ./script_name.sh

ou

. ./script_name.sh

Ce dernier est légèrement plus compatible entre différents obus.

Longue réponse

Cette question met en évidence un point important, à savoir que les scripts Shell sont exécutés dans leur propre contexte. Pour voir ce que cela signifie, considérons le script Shell suivant:

#!/bin/bash

cd /
ls

Si vous exécutez ceci, vous obtiendrez une sortie semblable à ceci:

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

Mais vous remarquerez qu'après avoir exécuté le script, vous êtes toujours dans le répertoire dans lequel vous vous trouviez avant de l'exécuter: le cd / du script n'a pas réellement affecté votre session, mais uniquement le contexte dans lequel le script était exécuté, créé pour l'exécution du script et détruit à son retour.

La commande source "lira et exécutera les commandes à partir de l'argument filename dans le contexte actuel du shell". Par conséquent, toutes les commandes telles que cd auront une incidence sur votre session en cours. Si vous deviez exécuter le script ci-dessus en le passant à source, vous découvririez que vous vous retrouviez dans le répertoire racine après son exécution.

Dans ce cas, le problème est que la commande history vous donne l'historique du contexte Shell en cours. le contexte Shell dans lequel votre script s'exécute sans utiliser __nom_variable__ n'a pas d'historique et n'écrit donc rien dans le fichier de sortie. Si vous utilisez source, il s'exécutera dans le contexte approprié et fonctionnera comme prévu.

NB: source est un shell intégré, pas un programme en soi - dans Bash, source est synonyme de ., mais dans certains shells, seul . fonctionnera - j'ai utilisé source, mais dans cette réponse, j'ai utilisé source c'est plus facile à lire que ., mais pour une compatibilité maximale, . devrait être utilisé.

11
p0llard

Tout d'abord, notez que votre historique est déjà dans un fichier. Si vous utilisez bash, son nom est généralement ~/.bash_history. Plus précisément, il s’agit de ce que vous avez défini pour la variable HISTFILEname__. Si vous voulez le copier dans un autre fichier, lancez simplement cat "$HISTFILE" > hist.txt

Maintenant, pour savoir pourquoi la commande historyne fonctionne pas dans un script shell bash, c'est parce que les scripts sont exécutés dans un shell enfant non interactif de votre session Shell actuelle. Les shells enfants n'héritent pas de tout l'environnement du parent (donc pas de toutes les variables définies), mais uniquement des variables exportées. À titre d’illustration, le script ci-dessous reprendra la valeur de la variable $var:

#!/bin/bash
echo "$var"

Maintenant, définissez $var sur quelque chose et exécutez le script:

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

Ensuite, exportez d'abord la variable:

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

Comme vous pouvez le constater, lorsque la variable a été exportée, elle est disponible pour les shells enfants.

Comme je l'ai déjà mentionné, l'historique est stocké dans le fichier désigné par la variable $HISTFILENAME. Parce que cela n’est pas exporté par défaut, il n’est pas défini lors de l’exécution d’un script:

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

Comme vous pouvez le voir dans l'exemple ci-dessus, la variable HISTFILEest définie dans ma session Shell normale, mais est vide lors de l'exécution du script.

Donc, pour avoir l'historique, vous avez quelques options:

  1. La valeur par défaut HISTFILEest $HOME/.bash_history. Si vous n'avez pas changé cela, vous pouvez simplement exécuter cette commande dans votre script:

    cat "$HOME/.bash_history" > history
    
  2. Vous pouvez transmettre la variable $HISTFILE à votre script et catqui:

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

    Enregistrez ce qui précède sous foo.sh et exécutez-le comme ceci:

    ./foo.sh "$HISTORY"
    
  3. Assurez-vous que la variable est exportée. Ajoutez cette ligne à vos fichiers ~/.bash_profile (s’il existe) ou ~/.profile (si ~/.bash_profile n'existe pas):

    export HISTFILE
    

    Ensuite, déconnectez-vous et reconnectez-vous et vous devriez pouvoir exécuter history > hist.txt à partir d'un script comme prévu. En effet, export VAR signifie "rendre $ VAR disponible pour les shells enfants". Concrètement, cela signifie que la valeur de HISTFILEsera héritée par le shell non interactif que vous utilisez pour exécuter votre script.

    Désormais, alors que HISTFILEsera défini, il n’a pas été lu par le shell qui exécute le script. Donc, pour que cela fonctionne, vous devez d'abord le lire avec history -r. Le script entier ressemblerait à ceci:

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

    Vous pouvez également l'exporter manuellement avant d'exécuter le script:

    $ export HISTFILE
    

    Mais vous aurez toujours besoin de history -r dans le script.

  4. Vous pouvez sourcele suggérer par la réponse de @ p0llard .

10
terdon