在shell中,我运行以下命令没有问题,
ls -al
!LS
对ls
的第二次调用也列出了带有-al
标志的文件。但是,当我将上述脚本放到bash脚本中时,会抛出投诉,
!ls, command not found.
如何在脚本中实现相同的效果?
答案 0 :(得分:5)
您需要在脚本中启用命令历史记录和!-style历史记录扩展(默认情况下在非交互式shell中都关闭):
set -o history
set -o histexpand
扩展命令也会响应标准错误,就像在交互式shell中一样。您可以通过启用histverify
shell选项(shopt -s histverify
)来阻止这种情况,但在非交互式shell中,这似乎会使历史记录扩展为空操作。
答案 1 :(得分:0)
好吧,我想让这个也工作,我必须告诉每个人set -o history ; set -o histexpand
方法将 在bash 4.x
中工作。无论如何,它并不意味着在那里使用,因为有更好的方法来实现这一点。
首先,这是一个相当简单的例子,只是想在脚本中执行 history
:
(仅 bash
4.x或更高)
#!/bin/bash -i
history
简短的回答:它有效!!
打屁股的新-i
选项代表交互式,history
将工作。但出于什么目的?
引用迈克尔H.来自OP的评论:
"虽然你可以启用它,但这是糟糕的编程习惯。它会使你的脚本(...)难以理解。默认情况下禁用它是有原因的。你为什么要这样做?"
是的,为什么?这个更深层次的感觉是什么? 嗯,有,我将在后续章节中演示。
我的history
缓冲区已经变得很大,而其中一些是脚本单行,我真的不想每次都重新输入。但有时,我也想改变这些行,因为我可能想要给出第三个参数,而我之前只需要两个。
所以这是使用bash
4.0+功能调用 history
的理想方式:
$ history
(...)
<lots of lines>
(...)
1234 while IFS='whatever' read [[ $whatever -lt max ]]; do ... ; done < <(workfile.fil)
<25 more lines>
因此 1234 来自历史正好我们想要的行。当然,我们可以使用鼠标并移动到那里,将整行放入主缓冲区?但是我们依靠* NIX,为什么我们不能让生活变得更轻松?
这就是我写下这个小脚本的原因。同样,这仅适用于bash
4.0+(但可能适用于bash
3.x及更早版本的上述set -o ...
内容...)
#!/bin/bash -i
[[ $1 == "" ]] || history | grep "^\s*$1" |
awk '{for (i=2; i<=NF; i++) printf $i" "}' | tr '\n' '\0'
例如,如果将其保存为xselauto.sh
,则可以调用
$ ./xselauto.sh 1234
并且history
行#1234的内容将位于主缓冲区中,可以重复使用!
现在,如果有人仍然说'#34;这没有目的AFAICS&#34;或者&#34;谁曾经需要这个功能?&#34; - 好吧,我不在乎。但是我不想再没有这个功能了,因为我每次都懒得重新输入复杂的线条。而且我也不想为历史上的每条标记线触摸鼠标TBH。这就是为xsel
写的。
BTW,管道的tr
部分是一个脏的黑客,它将阻止命令执行。对于&#34;危险&#34;命令,非常重要的是,在用户点击 Enter 键执行它之前,始终让用户选择外观。你可以省略它,但是......你已被警告过。
P.S。这个scriptlet实际上是一个变通方法,模拟在bash shell上键入的!1234
。由于我永远无法在脚本中!
直接工作(echo
永远不会让我透露历史记录第1234行的内容),我只需grep
我要复制的行就可以解决问题。
答案 2 :(得分:-2)
历史记录扩展是shell的交互式命令行编辑功能的一部分,而不是脚本语言的一部分。它通常不在脚本的上下文中,只有在与(伪)人类操作员交互时才可用。 (伪意味着可以使用expect
或其他按键重复自动化工具,这些工具通常会尝试扮演人类,而不是暗示任何特定的操作员可能是次人或任何东西。