使用 ”!”在脚本中执行具有相同参数的命令

时间:2012-08-23 18:34:03

标签: bash scripting

在shell中,我运行以下命令没有问题,

  

ls -al

     

!LS

ls的第二次调用也列出了带有-al标志的文件。但是,当我将上述脚本放到bash脚本中时,会抛出投诉,

!ls, command not found.

如何在脚本中实现相同的效果?

3 个答案:

答案 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或其他按键重复自动化工具,这些工具通常会尝试扮演人类,而不是暗示任何特定的操作员可能是次人或任何东西。