¿Cómo guardar el historial del terminal en un archivo desde un archivo bash?

7

Estoy tratando de crear un script bash que guardará el historial del terminal en un archivo llamado hist.txt. El uso history > hist.txtno parece funcionar en el script bash, pero funciona bien cuando se ejecuta en la línea de comando.

Cualquier orientación es muy apreciada.

Gracias Judy

Judy
fuente
3
Tu pregunta es un poco confusa. ¿Qué quieres decir con "no parece funcionar en el archivo bash, pero funciona bien cuando se ejecuta en la línea de comandos"? ¿Quiere decir que está tratando de guardar su historial de comandos desde un script bash que se está ejecutando? ¿Como desea guardar qué comandos ha ejecutado el script? El guión en sí mismo es una historia en este caso.
Stephen
66
¿O desea generar el historial de bash de un usuario en particular? Podrías leer el ~/.bash_historyarchivo del usuario .
Arronical
1
@Arronical tenga en cuenta que esto solo funcionará si el usuario está usando Bash como su shell, que no siempre es el caso.
1
@ p0llard Por supuesto, salté con la suposición de que, como estaba en un script de Bash, sería Bash como el shell del usuario, pero ese puede no ser el caso, como has dicho. Buenos detalles y antecedentes en su respuesta, por cierto.
Arronical

Respuestas:

11

Respuesta corta

Ejecute el script con sourceo .:

source ./script_name.sh

o

. ./script_name.sh

Este último es ligeramente más compatible en diferentes conchas.

Respuesta larga

Esta pregunta destaca un punto importante, que es que los scripts de shell se ejecutan en su propio contexto. Para ver lo que esto significa, considere el siguiente script de shell:

#!/bin/bash

cd /
ls

Si ejecuta esto, obtendrá un resultado similar a este:

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

Pero notará que después de ejecutar el script, todavía está en el directorio en el que se encontraba antes de ejecutarlo: el cd /interior del script no ha afectado realmente su sesión, solo afectó el contexto en el que se estaba ejecutando el script, que se crea para que se ejecute el script y se destruye una vez que vuelve.

El sourcecomando 'leerá y ejecutará comandos del argumento del nombre de archivo en el contexto actual del shell', por lo que cualquier comando como cdeste afectará su sesión actual. Si sourcetuviera que ejecutar el script anterior al pasarlo, encontraría que termina dentro del directorio raíz después de que se ejecutó.

En este caso, el problema es que el historycomando le proporciona el historial del contexto actual del shell; el contexto de shell en el que se ejecuta su script sin usar sourceno tiene historial, por lo que no escribe nada en el archivo de salida. Si lo usa source, se ejecutará en el contexto correcto y funcionará como se espera.

NB: sourcees un shell integrado, no un programa en sí mismo ; en Bash, sourcees sinónimo de ., pero en algunos shells solo .funcionará. Lo he usado sourceen esta respuesta porque es más fácil de leer que ., pero para una compatibilidad máxima, .debería ser usado.


fuente
Muy interesante lectura. Siempre me he preguntado acerca de los comandos de historial 'perdidos', ahora sé por qué. ¡Gracias!
Tico
10

En primer lugar, tenga en cuenta que su historial ya está en un archivo. Si está ejecutando bash, su nombre suele ser ~/.bash_history. Más específicamente, es lo que sea que haya configurado la variable HISTFILE. Si desea copiarlo a otro archivo, simplemente ejecutecat "$HISTFILE" > hist.txt

Ahora, por qué el historycomando no funciona en un script de shell bash, es porque los scripts se ejecutan en un shell hijo no interactivo de su sesión de shell actual. Los shells secundarios no heredan todo el entorno del padre (por lo tanto, no todas las variables establecidas), solo las variables que se han exportado. Para ilustrar, el siguiente script hará eco del valor de la variable $var:

#!/bin/bash
echo "$var"

Ahora, establece $varalgo y ejecuta el script:

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

A continuación, exporte la variable primero:

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

Como puede ver, cuando la variable se ha exportado, está disponible para shells secundarios.

Como mencioné antes, el historial se almacena en el archivo señalado por la variable $HISTFILENAME. Como eso no se exporta de forma predeterminada, no se establece cuando se ejecuta un script:

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

Como puede ver en el ejemplo anterior, la variable HISTFILEse establece en mi sesión de shell normal, pero está vacía cuando se ejecuta el script.

Entonces, para obtener el historial, tiene algunas opciones:

  1. El valor predeterminado HISTFILEvalor es $HOME/.bash_history. Si no ha cambiado eso, simplemente puede ejecutar este comando en su script:

    cat "$HOME/.bash_history" > history
  2. Puede pasar la $HISTFILEvariable a su script y cateso:

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

    Guarde lo anterior como foo.shy ejecute así:

    ./foo.sh "$HISTORY"
  3. Asegúrese de que la variable se exporte. Agregue esta línea a sus archivos ~/.bash_profile(si existe) o ~/.profile(si ~/.bash_profileno existe):

    export HISTFILE

    Luego, cierre la sesión y vuelva a iniciarla y debería poder ejecutar history > hist.txtdesde un script como se esperaba. Esto se debe a que export VARsignifica "poner $ VAR a disposición de los shells secundarios". En términos prácticos, esto significa que el valor de HISTFILEserá heredado por el shell no interactivo que utiliza para ejecutar su script.

    Ahora, aunque HISTFILEse establecerá, el shell no lo ha leído al ejecutar el script. Entonces, para que funcione, history -rprimero debes leerlo . El guión completo se vería así:

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

    Alternativamente, simplemente expórtelo manualmente antes de ejecutar el script:

    $ export HISTFILE

    Pero aún lo necesitarás history -ren el guión.

  4. Puede sourcehacerlo como lo sugiere la respuesta de @ p0llard .

terdon
fuente