问题
假设我刚刚输入此命令来获取包含特定字符串的行数:
me@machine $ command-producing-multi-line-output | grep -i "needle" | wc -l
现在我怎样才能快速地"needle"
用其他词替换呢?
当前低效的解决方案
现在我:
- 按
Up
键盘加载最后一条命令。 - 按
Left
或Ctrl
+Left
直到到达"needle"
。 - 按
Backspace
或Ctrl
+w
删除该单词。 - 输入或粘贴新单词。
- 打
Enter
。
这看起来效率很低。
尝试的无效解决方案
我尝试研究历史捷径,例如!!:sg/needle/new-needle
;但这有一些问题:
- 您无法
Up
按 回到!!:sg/needle/new-needle
命令行。这样做只会显示它扩展到什么(直接回到原来的问题)。 - 使用另一根新针重复此操作需要同时更换
needle
和new-needle
(即!!:sg/new-needle-from-before/yet-another-new-needle
)。 - 无论针有多长,您都需要键入整个内容
needle
,而不是使用类似!:4
或$4
(即!!:sg/!:4/new-needle
或)之类的内容来节省时间/击键。!!:sg/$4/new-needle
我也发现了类似的事情!:^-3 "new-needle" !:5-$
,但也有问题:
- 它会在历史中扩展,因此无法快速重复使用。
- 即使它没有扩展,您也会遇到最初的问题,即需要替换命令链中间的单词。
我相信必须有一些超级快速的方法来完成我想做的事情,并且一些 Linux 专家都知道这一点。如果您对此有任何意见或建议,我将不胜感激。
编辑:
背景
简单介绍一下背景知识,我经常在命令行上使用 OpenStack,我发现自己经常需要在管道命令的长命令链中的多个位置替换参数。
我们的 OpenStack 环境配置方式是,多个工程师stack
在任意数量的服务器上共享一个用户,并且多个环境中存在多个集群。因此,在.bashrc
或文件中声明的函数.profile
实际上是不可能的。
我希望有一些便携式设备可以快速使用,无需或只需要很少的设置。否则,我可能只需要完全使用 shell 之外的解决方案(例如 AutoHotKey/Keyboard Maestro/AutoKey 中的剪贴板替换等)。
答案1
那是确切地什么历史扩展用于:
$ command-producing-multi-line-output | grep -i "needle" | wc -l
...
$ ^needle^nipple
command-producing-multi-line-output | grep -i "nipple" | wc -l
...
答案2
我遇到过类似的情况,并在这里提出我的解决方案,以防万一它是一个有用的模式。
一旦我意识到我正在反复更改一段数据,而交互式替换很烦人,我就会停下来编写一个小循环while
:
$ command-producing-multi-line-output | grep -i "needle" | wc -l
0
$ command-producing-multi-line-output | grep -i "haystack" | wc -l
0
$ while read needle; do
Up-Arrow到上一行command-producing-multi-line-output
并替换"haystack"
为"$needle"
command-producing-multi-line-output | grep -i "$needle" | wc -l; done
something
0
something else
0
gold
1
Control(以+结尾D)
或者稍微花哨一点的变体:
$ while read needle; do
printf 'For: %s\n' "$needle"
command-producing-multi-line-output | grep -i "$needle" | wc -l; done
如果我看到这个命令行的未来超越“今天”,我会将其写入函数或脚本中。
答案3
一个有用的别名bash
是
alias r='fc -s'
默认情况下,该r
命令经常在其他 shell 中找到1,并重复历史上最近的命令。该bash
手册甚至将此作为定义的有用别名:
[...] A useful alias to use with this is ``r="fc -s"'',
so that typing ``r cc'' runs the last command beginning with
``cc'' and typing ``r'' re-executes the last command.
它还允许您在最后一个命令的文本中进行替换。
在这里,我运行您的命令,然后使用上面的别名将单词替换needle
为单词haystack
:
$ command-producing-multi-line-output | grep -i "needle" | wc -l
bash: command-producing-multi-line-output: command not found
0
$ r needle=haystack
command-producing-multi-line-output | grep -i "haystack" | wc -l
bash: command-producing-multi-line-output: command not found
0
当我r needle=haystack
在命令行上使用时,外壳程序会打印出它将要运行的命令,然后立即运行它。正如您所看到的,它也取代了这个词。
这些错误显然是由于我没有command-producing-multi-line-output
命令造成的,但这在本练习中并不重要。
该fc
命令不会保存到您的历史记录中,但您可以通过将其创建为 shell 函数来保存它,如下所示:
fc() {
command fc "$@"
history -s fc "$@" # append the given fc command to history
}
然后你可以这样做
$ command-producing-multi-line-output | grep -i "needle" | wc -l
bash: command-producing-multi-line-output: command not found
0
重新运行以以下开头的最新命令comm
并替换needle
为r needle=haystack comm
:
$ r needle=haystack comm
command-producing-multi-line-output | grep -i "haystack" | wc -l
bash: command-producing-multi-line-output: command not found
0
重新运行最近的命令,但haystack
使用以下命令替换r haystack=beeswax
:
$ r haystack=beeswax
fc -s needle=beeswax comm
command-producing-multi-line-output | grep -i "beeswax" | wc -l
bash: command-producing-multi-line-output: command not found
0
fc
请注意最后一行中的双重调用,首先通过我们的别名r
,然后通过我们的 function fc
。
显然,将fc
命令保存到历史记录会使您面临意外递归调用的风险fc -s
。
1它是zsh
一个内置命令,在 OpenBSD 中ksh
它是 的默认别名fc -s
,在ksh93
它是 的默认别名hist -s
,等等。
答案4
摘要:Ctrl++R nee
AltD haystack
Enter
按Ctrl+R开始反向增量搜索并键入要替换的文本的几个字符(或一些与其非常接近的文本),直到出现所需命令行的所需部分(它不必是上一个命令行)。按Ctrl+R搜索上一个出现的位置。如果您后退得太远,请按Ctrl+S前进。Backspace如果您输错了字符,请按此键。
到达所需位置后,您可以使用Delete、Alt+D或Alt+等键Backspace开始删除光标周围的文本,或者只是Escape在到达的位置退出增量搜索。
Enter仅当您完成命令行编辑后才按此键。请注意,Enter在增量搜索期间,其正常含义是按原样执行当前命令行:它不只是退出搜索模式(按Escape即可退出搜索模式)。