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


7

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

任何指导,不胜感激。

谢谢朱迪


3
您的问题有点令人困惑。您的意思是“似乎无法在bash文件中工作,但在命令行中执行时效果很好”?您是说要从正在执行的bash脚本中保存命令历史记录吗?如您希望保存的那样,脚本已执行了哪些命令?在这种情况下,脚本本身就是一个历史。
斯蒂芬

6
还是要输出特定用户的bash历史记录?您可以只读取用户的~/.bash_history文件。
Arronical's

1
@Arronical注意,这仅在用户使用Bash作为其外壳程序时才有效,但并非总是如此。

1
@ p0llard当然,我以Bash脚本中的假设为前提,它将以Bash作为用户的外壳程序,但事实并非如此,正如您所说。顺便说一句,答案中的细节和背景都很好。
Arronical '16

Answers:


11

简短答案

使用source或运行脚本.

source ./script_name.sh

要么

. ./script_name.sh

后者在不同外壳之间的兼容性更高。

长答案

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

#!/bin/bash

cd /
ls

如果运行此命令,将得到类似以下的输出:

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

但是您会注意到,运行脚本后,您仍在运行脚本之前所在的目录中:cd /脚本内部实际上并未影响您的会话-它仅影响了脚本在其中运行的上下文,被创建用于脚本运行,并在返回时销毁。

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

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

注意:这source是内置的shell,本身不是程序-在Bash中source是的代名词.,但在某些shell中只能.用-我source在此答案中使用过,因为它比容易阅读.,但为了最大程度地兼容,.应该使用。


非常有趣的阅读。我一直想知道“缺少”历史命令,现在我知道为什么了。谢谢!
Tico

10

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

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

#!/bin/bash
echo "$var"

现在,设置$var为某种并运行脚本:

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

接下来,首先导出变量:

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

如您所见,导出变量后,子外壳程序即可使用它。

如前所述,历史记录存储在变量所指向的文件中$HISTFILENAME。由于默认情况下不会导出该文件,因此在运行脚本时不会将其设置:

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

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

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

  1. 默认HISTFILE值为$HOME/.bash_history。如果尚未更改,则可以在脚本中运行以下命令:

    cat "$HOME/.bash_history" > history
  2. 您可以将$HISTFILE变量传递给脚本,cat这样:

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

    将以上内容另存为foo.sh,然后像这样运行:

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

    export HISTFILE

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

    现在,虽然HISTFILE将设置,但是运行脚本的shell尚未读取它。因此,要使其正常工作,您需要先阅读它history -r。整个脚本如下所示:

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

    另外,可以在运行脚本之前手动将其导出:

    $ export HISTFILE

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

  4. 您可以source按照@ p0llard的答案的建议进行操作

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.