简短答案

简短答案

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

非常感谢任何指导。

谢谢你朱迪

答案1

简短答案

source使用或运行脚本.

source ./script_name.sh

或者

. ./script_name.sh

后者在不同的 shell 之间的兼容性稍微好一些。

长答案

这个问题突出了一个重要点,即 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在这个答案中使用了 ,因为它比 更容易阅读.,但为了最大限度地兼容,.应该使用。

答案2

首先,请注意,您的历史记录已在文件中。如果您正在运行 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

如您所见,当变量被导出后,子 shell 就可以使用它。

正如我之前提到的,历史记录存储在变量指向的文件中$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将由您用于运行脚本的非交互式 shell 继承。

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

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

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

    $ export HISTFILE
    

    但您仍然需要history -r在脚本中这样做。

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

相关内容