如何重新运行管道中的第 k 个命令?

如何重新运行管道中的第 k 个命令?

我有以下管道:

➜  echo ,cats,and,dogs, | sed -e 's/,[^,]*,[^,]*,/,,,/'
,,,dogs,

我知道我可以运行诸如!!“运行最后一个命令”或!:1“获取最后一个参数”之类的命令,但我想知道是否有一些我可以运行的命令可以让我“k从管道”

因此,在这个示例中,如果我想将一些其他输出通过管道传输到sed实用程序中,我可以在运行上述管道后立即执行类似的操作:

$ echo ,foo,bar,baz, | %:2

哪里%:2有一些我不知道的可能虚构的命令,“k在管道中运行第一个命令”这个命令是否存在?

答案1

历史扩展在 80 年代(由 引入csh)非常巨大,当时终端非常缓慢且有限。但问题是它们不是所见即所得。你看不到它扩展成什么,直到为时已晚(命令已经启动)(尽管有些 shell 允许在按 Enter 键之前执行扩展)。

在这里,我将创建一个小部件,用于在光标处插入最后一个管道元素。与zsh(将其添加到~/.zshrc):

last-pipe-elements() {
  emulate -L zsh
  if [[ $WIDGET = $LASTWIDGET ]]; then
    # Invoking the widget several times retrieves pipeline
    # elements for older command lines
    ((last_pipe_elements_iteration++))
    LBUFFER=$last_pipe_elements_saved_LBUFFER
  else
    last_pipe_elements_iteration=1
  fi
  last_pipe_elements_saved_LBUFFER=$LBUFFER

  local -a words
  words=(${(z)${history[@]}[last_pipe_elements_iteration]})

  local nth_pipe=${words[(In:NUMERIC:)\|]}
  ((nth_pipe)) || return

  LBUFFER+=${(j: :)words[nth_pipe,-1]}
}
zle -N last-pipe-elements
bindkey '\eP' last-pipe-elements

这样,您输入Alt+Shift+P(这里假设发送 ESC 和P字符序列,您可能需要根据终端进行调整,终端可能会发送\xd0$'\MP')甚至\xf0($'\Mp')或完全不同的东西,请使用检查Ctrl+V)以插入最后一个命令的最后一个管道元素(包括|),再次按下它以执行之前的命令,并用于Alt+2Alt+Shift+P最后 2 个管道元素。

(z)调用 shell 解析器将命令行拆分为单词。我们找到|我们想要的,然后将其右侧的单词与空间。这意味着它将|tr a b成为| tr a b,但只要您不使用复杂的多行结构(例如sed 's/ /x/'不会更改为),就不应该影响命令的含义。sed 's/ /x/'

如果您不想定义新的小部件,您可以做的另一件事是向后搜索(使用Ctrl+R假设模式,尽管您可以在模式emacs中执行等效操作) ,删除到行尾并返回到您的命令 ( ) 将其粘贴到.这仍然比使用历史扩展更快,并且仍然是可视的(您可以更好地直观地选择要从中剪切的内容)。vi|Ctrl+KDownCtrl+Y|

答案2

不知道如何“在管道之后”,但“在第三个空格之后”可能会有所帮助:

$ echo ,cats,and,dogs, | sed -e 's/,[^,]*,[^,]*,/,,,/'
,,,dogs,
$ echo ,cat,and,mouse, | !:3-$
,,,mouse,

“管道后”的解决方法:

$ echo ,cats,and,dogs, | sed -e 's/,[^,]*,[^,]*,/,,,/'
,,,dogs,
$ after_pipe="$(cut -d "|" -f 2- <<<"!!" )"
$ echo ,cat,and,mouse, | eval "$after_pipe"
$ ,,,mouse,

cut如果第一个命令中有带引号的管道“|”,则需要更好的东西。)

相关内容