如何快速替换管道命令链中的参数

如何快速替换管道命令链中的参数

问题

假设我刚刚输入此命令来获取包含特定字符串的行数:

me@machine $ command-producing-multi-line-output | grep -i "needle" | wc -l

现在我怎样才能快速地"needle"用其他词替换呢?


当前低效的解决方案

现在我:

  1. Up键盘加载最后一条命令。
  2. LeftCtrl+Left直到到达"needle"
  3. BackspaceCtrl+w删除该单词。
  4. 输入或粘贴新单词。
  5. Enter

这看起来效率很低。


尝试的无效解决方案

我尝试研究历史捷径,例如!!:sg/needle/new-needle;但这有一些问题:

  1. 您无法Up按 回到!!:sg/needle/new-needle命令行。这样做只会显示它扩展到什么(直接回到原来的问题)。
  2. 使用另一根新针重复此操作需要同时更换needlenew-needle(即!!:sg/new-needle-from-before/yet-another-new-needle)。
  3. 无论针有多长,您都需要键入整个内容needle,而不是使用类似!:4$4(即!!:sg/!:4/new-needle或)之类的内容来节省时间/击键。!!:sg/$4/new-needle

我也发现了类似的事情!:^-3 "new-needle" !:5-$,但也有问题:

  1. 它会在历史中扩展,因此无法快速重复使用。
  2. 即使它没有扩展,您也会遇到最初的问题,即需要替换命令链中间的单词。

我相信必须有一些超级快速的方法来完成我想做的事情,并且一些 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并替换needler 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如果您输错了字符,请按此键。

到达所需位置后,您可以使用DeleteAlt+DAlt+等键Backspace开始删除光标周围的文本,或者只是Escape在到达的位置退出增量搜索。

Enter仅当您完成命令行编辑后才按此键。请注意,Enter在增量搜索期间,其正常含义是按原样执行当前命令行:它不只是退出搜索模式(按Escape即可退出搜索模式)。

相关内容