如何将终端历史记录从 bash 文件保存到文件?

Jud*_*udy 7 bash scripts logging history

我正在尝试创建一个 bash 脚本,它将终端历史记录保存到一个名为 hist.txt 的文件中。history > hist.txt在 bash 脚本中使用似乎不起作用,但在命令行中执行时工作正常。

非常感谢任何指导。

谢谢朱迪

小智 11

简答

使用source或运行脚本.

source ./script_name.sh
Run Code Online (Sandbox Code Playgroud)

或者

. ./script_name.sh
Run Code Online (Sandbox Code Playgroud)

后者在不同的 shell 中稍微更兼容。

长答案

这个问题突出了一个重点,即 shell 脚本在它们自己的上下文中运行。要了解这意味着什么,请考虑以下 shell 脚本:

#!/bin/bash

cd /
ls
Run Code Online (Sandbox Code Playgroud)

如果你运行这个,你会得到这样的输出:

bin  boot  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
Run Code Online (Sandbox Code Playgroud)

但是您会注意到,在运行脚本之后,您仍然在运行它之前所在的任何目录中:cd /脚本内部实际上并没有影响您的会话——它只影响了运行脚本的上下文,即为运行脚本而创建,并在它返回后销毁。

source命令将“从当前 shell 上下文中的文件名参数读取和执行命令”,因此任何类似cd其中的命令都会影响您的当前会话。如果您通过将其传递给上面的脚本来运行它,source您会发现它运行后最终位于根目录中。

在这种情况下,问题在于该history命令为您提供了当前 shell 上下文的历史记录;您的脚本在不使用的情况下运行的 shell 上下文source没有历史记录,因此它不会向输出文件写入任何内容。如果您使用source它,它将在正确的上下文中执行,并按预期工作。

注意:source是一个内置的 shell,而不是一个程序本身——在 Bash 中,source是 的同义词.,但在某些 shell 中只能.工作——我source在这个答案中使用了它,因为它比 更容易阅读.,但为了最大的兼容性,.应该使用。


ter*_*don 10

首先,请注意您的历史记录已经在一个文件中。如果您正在运行 bash,它的名称通常是~/.bash_history. 更具体地说,它是您将变量设置为的任何内容HISTFILE。如果要将其复制到另一个文件,只需运行cat "$HISTFILE" > hist.txt

现在,至于为什么该history命令在 bash shell 脚本中不起作用,那是因为脚本在当前 shell 会话的非交互式子 shell 中运行。子 shell 不会继承父级的所有环境(因此不是所有设置的变量),只有已导出的变量。为了说明,下面的脚本将回显变量的值$var

#!/bin/bash
echo "$var"
Run Code Online (Sandbox Code Playgroud)

现在,设置$var一些东西并运行脚本:

$ var="foo"
$ foo.sh
VAR: 
Run Code Online (Sandbox Code Playgroud)

接下来,首先导出变量:

$ var="foo"
$ export var
$ foo.sh
VAR: foo
Run Code Online (Sandbox Code Playgroud)

如您所见,导出变量后,它可用于子 shell。

正如我之前提到的,历史记录存储在变量指向的文件中$HISTFILENAME。因为默认情况下不会导出,所以在运行脚本时不会设置它:

$ cat foo.sh
#!/bin/bash
echo "HISTFILE: $HISTFILE"
$ ./foo.sh
HISTFILE:
$ echo $HISTFILE
/home/terdon/.bash_history
Run Code Online (Sandbox Code Playgroud)

正如您在上面的示例中看到的,该变量HISTFILE是在我的正常 shell 会话中设置的,但在运行脚本时为空。

因此,要获取历史记录,您有几个选择:

  1. 默认HISTFILE值为$HOME/.bash_history。如果你没有改变它,你可以简单地在你的脚本中运行这个命令:

    cat "$HOME/.bash_history" > history
    
    Run Code Online (Sandbox Code Playgroud)
  2. 您可以将$HISTFILE变量传递给脚本,cat然后:

    #!/bin/bash
    cat "$1" > history
    
    Run Code Online (Sandbox Code Playgroud)

    将上面的另存为foo.sh并像这样运行:

    ./foo.sh "$HISTORY"
    
    Run Code Online (Sandbox Code Playgroud)
  3. 确保变量已导出。将此行添加到您的~/.bash_profile(如果存在)或~/.profile(如果~/.bash_profile不存在)文件中:

    export HISTFILE
    
    Run Code Online (Sandbox Code Playgroud)

    然后,注销并重新登录,您应该能够history > hist.txt按预期从脚本运行。这是因为export VAR意味着“使 $VAR 可用于子 shell”。实际上,这意味着HISTFILE用于运行脚本的非交互式 shell 将继承的值。

    现在,虽然HISTFILE设置了will,但运行脚本的 shell 还没有读取它。所以,要让它工作,你需要先阅读它history -r。整个脚本如下所示:

    $!/bin/bash
    history -r
    history > hist.txt
    
    Run Code Online (Sandbox Code Playgroud)

    或者,只需在运行脚本之前手动导出它:

    $ export HISTFILE
    
    Run Code Online (Sandbox Code Playgroud)

    但是你仍然需要history -r在脚本中。

  4. 您可以source按照@p0llard's answer 的建议进行操作