无法在脚本中使用!$?


11

只是想知道为什么这不起作用

#!/bin/bash 

ls /bin
ls !$

我预计会运行ls /bin两次,但是第二次会出现错误,!$因为没有解释

我错过了什么,还是!$只在命令行工作?

我在man bash(Mac上)找不到相关的部分


9
尽管有解决方案,但这真的是在脚本中实现此目标的最佳方法吗?由于非交互式运行时,默认情况下会禁用历史记录-长脚本将对.bash_history文件进行垃圾邮件处理。并不是说这是不值得提出的问题,而是如果您正在考虑在脚本中使用它,那真的是最好的方法吗?
flungo '16

Answers:


26

当Shell非交互运行时,默认情况下禁用历史记录历史记录扩展

你需要:

#!/bin/bash 

set -o history
set -o histexpand

ls /bin
ls !$

要么:

SHELLOPTS=history:histexpand bash script.sh

它会影响所有script.sh可能运行的bash实例。


9
谨慎使用SHELLOPTS,这将影响bash运行script.sh,但也会影响最终可能运行的所有其他bash实例script.sh(如其他bash脚本...)。
斯特凡Chazelas

而且它不会影响任何其他 bash运行脚本的实例。
Blacklight Shining

我认为,如果将@StéphaneChazelas的评论编辑到其中,此答案将会有所改善。
Oliphaunt-恢复莫妮卡

7

理智的事情是

ls /bin
ls $_

要么

set ls /bin
$*
$*

要么

c='ls /bin'
$c
$c

注意事项:值得记住的是,每一个都有一些陷阱。$ _解决方案仅捕获最后一个参数:因此,ls foo bar将使$ _包含just bar。使用一个set将覆盖参数($1$2,等)。并且所有这些文字都可以使用,但是当推广到更复杂的命令(转义和空格很重要)时,您可能会遇到一些困难。例如:(ls 'foo bar'其中单个pathname参数foo bar包含两个或多个空格,或任何其他空格字符)在以上两个示例中的任何一个中均无法正常工作。为了避免这些情况,可能需要适当的转义(可能与eval命令组合)或使用"$@"代替$*


1
+1是可移植且不会滥用旨在简化交互使用的bashism的答案。(顺便说一句,bash在默认设置中以交互方式扩展感叹号的愿望与其他shell用户不同,我发现这是违反直觉的,并且适得其反,因为当我尝试执行一些复杂的shell命令时,它总是使我感到困惑)。
mtraceur '16

尽管正如目前写的那样,由于初学者shell脚本编写者在试图将其推广到更复杂的命令时可能遇到的问题,我还是犹豫是否给它+1。我建议进行编辑,至少要添加一个警告段落,解释其可能存在的陷阱。
mtraceur '16

@mtraceur:它不是可移植的,仅适用于bash,zsh,ksh(如果两个命令不在同一行中)。仅在交互时才在破折号,mksh中工作
cuonglm '16

@cuongim:对不起,我可能太粗心了。该$_方法是不可移植的,你是对的。该set方法适用于非交互式破折号,并且${1+"$@"}(加上zsh全局别名)技巧应该是通用的,尽管我模糊地记得它set的历史不能完全移植某些(旧的)shell。eval据我所知,特别是使用适当的转义和实际命令,定义一个变量来保存命令然后进行评估的方法通常是完全可移植的。
mtraceur '16
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.