Bash Shell中调取历史指定命令所有参数的问题咨询
我来帮你搞定这个Shell历史参数的小麻烦!你遇到的两个问题——!ls:!*报错、带选项的命令把选项传给后续命令导致异常——都有对应的解决办法,咱们一步步说:
一、正确调取特定命令的所有参数(替代!ls:1-3)
你之前用file !ls:1-3能拿到所有参数,但其实有更简洁的写法,而且能避免!ls:!*的报错:
直接用 !command:* 的语法,其中command是你要调取的历史命令(比如ls)。比如:
- 先执行
ls f1 f2 f3 - 再执行
file !ls:*
这条命令会直接展开成 file f1 f2 f3,完美替代你之前的!ls:1-3,而且不管参数有多少个都适用。
为什么!ls:!*会报错?
!*本身是调取上一条命令的所有参数,当你把它写在!ls:后面时,Shell会误以为你要给!ls加一个修饰符,但!不是合法的修饰符,所以才会出现-bash: !: unrecognized history modifier的错误。而*在历史扩展里表示“所有参数”,所以!ls:*才是正确的写法。
二、过滤命令中的选项,只获取非选项参数
如果你的命令带选项(比如ls -l f1 f2),直接用!ls:*会把-l也传给file,导致file把它当成自己的选项运行,结果肯定不对。这里有两种解决思路:
1. 固定跳过前N个参数(适合选项数量固定的场景)
如果知道命令的选项有几个,比如ls -l只有1个选项,那可以用!command:N-$的语法,从第N个参数取到最后一个:
- 先执行
ls -l f1 f2 - 再执行
file !ls:2-$
这条命令会展开成 file f1 f2,跳过了第一个参数-l。如果是ls -la f1 f2(两个选项),就改成!ls:3-$就行。
2. 自动过滤所有选项(灵活通用)
要是选项数量不固定,用上面的方法就太麻烦了。可以结合fc命令和awk来自动过滤掉所有以-开头的选项:
- 先执行
ls -la f1 f2 f3 - 再执行:
file $(fc -ln -1 ls | awk '{for(i=2;i<=NF;i++) if($i !~ /^-/) print $i}')
解释一下这条命令:
fc -ln -1 ls:输出最近一次ls命令的完整内容(不带行号)awk部分:从第2个字段开始(跳过命令本身ls),只打印不以-开头的参数,也就是文件名- 最后把这些文件名传给
file命令,完美避开所有选项
这样不管你给ls加多少个选项,都能准确提取出文件名参数。
内容的提问来源于stack exchange,提问作者Ibrahim Quraish

