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

7

J'essaie de créer un script bash qui enregistrera l'historique du terminal dans un fichier appelé hist.txt. L'utilisation history > hist.txtne semble pas fonctionner dans le script bash, mais fonctionne très bien lorsqu'elle est exécutée dans la ligne de commande.

Tout conseil est grandement apprécié.

Merci Judy

Judy
la source
3
Votre question est un peu déroutante. Que voulez-vous dire par "ne semble pas fonctionner dans le fichier bash, mais fonctionne très bien lorsqu'il est exécuté en ligne de commande"? Voulez-vous dire que vous essayez de sauvegarder votre historique de commandes à partir d'un script bash en cours d'exécution? Comme vous souhaitez enregistrer quelles commandes ont été exécutées par le script? Le script lui-même est une histoire dans ce cas.
Stephen
6
Ou souhaitez-vous afficher l'historique de bash d'un utilisateur particulier? Vous pouvez simplement lire le ~/.bash_historyfichier de l'utilisateur .
Arronical
1
@Arronical note que cela ne fonctionnera que si l'utilisateur utilise Bash comme shell, ce qui n'est pas toujours le cas.
1
@ p0llard Bien sûr, je me suis lancé en supposant que, comme c'était dans un script Bash, ce serait Bash comme shell de l'utilisateur, mais ce n'est peut-être pas le cas, comme vous l'avez dit. Bon détail et fond dans votre réponse BTW.
Arronical

Réponses:

11

Réponse courte

Exécutez le script avec sourceou .:

source ./script_name.sh

ou

. ./script_name.sh

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

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érez le script shell suivant:

#!/bin/bash

cd /
ls

Si vous exécutez ceci, vous obtiendrez une sortie quelque chose comme 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: l' cd /intérieur du script n'a pas réellement affecté votre session - il n'a affecté que le contexte dans lequel le script s'exécutait, ce qui est créé pour que le script s'exécute et détruit une fois qu'il est revenu.

La sourcecommande «lira et exécutera les commandes à partir de l'argument du nom de fichier dans le contexte shell actuel», donc toutes les commandes comme à l' cdintérieur affecteront votre session en cours. Si vous deviez exécuter le script ci-dessus en le passant, sourcevous 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 historycommande vous donne l'historique du contexte shell actuel; le contexte shell dans lequel votre script s'exécute sans utiliser sourcen'a pas d'historique, il n'écrit donc rien dans le fichier de sortie. Si vous l'utilisez, sourceil s'exécutera dans le bon contexte et fonctionnera comme prévu.

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


la source
Lecture très intéressante. Je me suis toujours posé des questions sur les commandes d'historique «manquantes», maintenant je sais pourquoi. Merci!
Tico
10

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, c'est ce que vous avez défini pour la variable HISTFILE. Si vous souhaitez le copier dans un autre fichier, lancez simplementcat "$HISTFILE" > hist.txt

Maintenant, pour savoir pourquoi la historycommande ne 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 toutes les variables définies), seulement les variables qui ont été exportées. Pour illustrer, le script ci-dessous fera écho à la valeur de la variable $var:

#!/bin/bash
echo "$var"

Maintenant, définissez $varquelque 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 voir, lorsque la variable a été exportée, elle est disponible pour les shells enfants.

Comme je l'ai mentionné précédemment, l'historique est stocké dans le fichier pointé par la variable $HISTFILENAME. Parce que ce 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 obtenir l'historique, vous avez quelques options:

  1. La HISTFILEvaleur par défaut est $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 passer la $HISTFILEvariable à votre script et catcela:

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

    Enregistrez ce qui précède sous foo.shet exécutez comme ceci:

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

    export HISTFILE

    Ensuite, déconnectez-vous et reconnectez-vous et vous devriez pouvoir exécuter à history > hist.txtpartir d'un script comme prévu. C'est parce que export VARsignifie "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.

    Maintenant, alors que le HISTFILEsera défini, il n'a pas été lu par le shell exécutant le script. Donc, pour le faire fonctionner, vous devez d'abord le lire 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 en aurez toujours besoin history -rdans le script.

  4. Vous pouvez le sourcefaire comme suggéré par la réponse de @ p0llard .

terdon
la source