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

Jef*_*ves 11 command-line bash command-history

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

me@machine $ command-producing-multi-line-output | grep -i "needle" | wc -l
Run Code Online (Sandbox Code Playgroud)

现在我怎么能快速"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在任意数量的服务器上共享一个用户,并且在多个环境中有多个集群。所以在.bashrcor.profile文件中声明的函数实际上是不可能的。

我希望有一些便携式的东西可以快速使用,不需要或只需要很少的设置。否则,我可能只需要完全在外壳之外使用解决方案(例如 AutoHotKey/Keyboard Maestro/AutoKey 中的剪贴板替换等)。

mos*_*svy 11

究竟是什么历史扩展是:

$ command-producing-multi-line-output | grep -i "needle" | wc -l
...
$ ^needle^nipple
command-producing-multi-line-output | grep -i "nipple" | wc -l
...
Run Code Online (Sandbox Code Playgroud)

  • 这是针对您的 Q 中难以理解的部分的有效解决方案,让那些通过搜索结果找到它的人受益。如果你想要一个可重用的命令,那么 __use 一个函数!__ 如果你想知道“如何在历史记录中保存未扩展的命令行?”,然后问一个单独的 Q。对于 Q 中“当前效率低下”的部分,我建议您阅读一些 emacs 或 vi 教程,具体取决于您使用的行编辑模式。 (3认同)

Jef*_*ler 10

我遇到了类似的情况,并在这里提出我的解决方案,以防万一它是一个有用的模式。

一旦我意识到我正在反复更改一段令人讨厌的数据以交互方式替换,我将停下来写一个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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

(以Control+结尾D

或者稍微更高级的变体:

$ while read needle; do
printf 'For: %s\n' "$needle"
command-producing-multi-line-output | grep -i "$needle" | wc -l; done
Run Code Online (Sandbox Code Playgroud)

如果我看到这个命令行超越“今天”的未来,我会把它写成一个函数或脚本。


Kus*_*nda 8

一个有用的别名bash

alias r='fc -s'
Run Code Online (Sandbox Code Playgroud)

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.
Run Code Online (Sandbox Code Playgroud)

它还允许您在最后一个命令的文本中进行替换。

在这里,我正在运行您的命令,然后我使用上面的别名将单词替换needle为单词haystack

alias r='fc -s'
Run Code Online (Sandbox Code Playgroud)
[...]  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.
Run Code Online (Sandbox Code Playgroud)

当我r needle=haystack在命令行上使用时,shell 会打印出它要运行的命令,然后立即运行它。如您所见,它也替换了这个词。

错误显然是由于我没有command-producing-multi-line-output命令造成的,但这在本练习中并不重要。


fc命令不会保存到您的历史记录中,但您可以通过将其创建为 shell 函数来保存它,如下所示:

$ command-producing-multi-line-output | grep -i "needle" | wc -l
bash: command-producing-multi-line-output: command not found
       0
Run Code Online (Sandbox Code Playgroud)

然后你可以做

$ r needle=haystack
command-producing-multi-line-output | grep -i "haystack" | wc -l
bash: command-producing-multi-line-output: command not found
       0
Run Code Online (Sandbox Code Playgroud)

重新运行最近的命令,commneedle使用r needle=haystack comm以下命令替换:

fc() {
    command fc "$@"
    history -s fc "$@"   # append the given fc command to history
}
Run Code Online (Sandbox Code Playgroud)

重新运行最近的命令,但haystack使用r haystack=beeswax以下命令替换:

$ command-producing-multi-line-output | grep -i "needle" | wc -l
bash: command-producing-multi-line-output: command not found
       0
Run Code Online (Sandbox Code Playgroud)

请注意fc在最后一行中进行的双重调用,首先通过我们的别名r,然后通过我们的函数fc

显然,将fc命令保存到历史记录会使您冒着意外fc -s递归调用的风险。


1zsh它是一个内置的命令,OpenBSD中ksh它是一个默认的别名fc -s,在ksh93它的默认别名hist -s等。


ica*_*rus 5

OP 说在 in.bashrc中声明的函数不实用,但没有什么可以阻止以交互方式声明一个函数。由于这仅适用于当前会话,因此可以使用单个字母名称,例如q.

从...开始

$ command-producing-multi-line-output | grep -i "haystack" | wc -l
Run Code Online (Sandbox Code Playgroud)

Up ;}结束一个函数,编辑haystackto $1, Control+aq(){Space得到

q(){ command-producing-multi-line-output | grep -i "$1" | wc -l;}
Run Code Online (Sandbox Code Playgroud)

那么你可以使用q needle, q haystack, q something。我更喜欢while当前接受的答案中的解决方案,因为它允许在搜索/计数之间使用其他命令。

对于这种特殊情况,我实际上会定义

q(){ command-producing-multi-line-output | grep -i "$@";}
Run Code Online (Sandbox Code Playgroud)

因为我可能希望在某个阶段看到实际匹配的线条,所以我可以使用q needle | wc -l或更好q -c needle地计数,并q needle查看线条。

由于函数定义将存储在 bash 历史记录中,如果在以后的会话中需要,通常可以重新加载定义。