【问题标题】:Use pipe ("|") as first symbol in bash or zsh command在 bash 或 zsh 命令中使用管道(“|”)作为第一个符号
【发布时间】:2020-02-29 14:51:52
【问题描述】:

我有两个简单的脚本:

./cpthat

BlueM/cliclick 在键盘上键入:Shift+Cmd+A,然后 Cmd+C,到活动的iTerm 终端:

#!/bin/zsh
cliclick kd:shift,cmd t:a ku:shift t:c ku:cmd
pbpaste>$THATF
  • Shift+Cmd+A 选择 上一个命令的输出,和
  • Cmd+C 复制“那个”到剪贴板。
  • pbpaste 然后写入到文件 $THATF 定义系统范围。

./that

#!/bin/zsh
cat $THATF

这会打印出cpthat 存储的最后一个命令的输出。

(我知道我可以直接运行$ command > $THATF,但由于其他原因,我需要对命令输出进行追溯。另外,不是线程安全的。)

挑战:

我正在尝试使用管道启动 zshbash 命令:

$ |grep -i sometext

实际上,这种情况发生在哪里:

$ that|grep -i sometext

这有可能吗?

  • 覆盖管道运算符?
  • zsh 配置魔法?
  • 我大量使用 zsh,但我愿意接受任何解决方案。

【问题讨论】:

    标签: bash macos pipe zsh magrittr


    【解决方案1】:

    您不需要以| 开头。 grep 实用程序自然会读取 STDIN

    这是一个人为的例子:

    # /bin/sh
    # count_matches
    grep $1 | wc -l
    
    $ cat file | count_matches thing
    

    您可以看到您要查找的 | 在命令行本身上,而不是在脚本中

    同样有效:

    $ count_matches thing < file
    

    在第一个示例中,STDIN 连接(通过管道)到第一个命令的输出(通常是 cat)。第二,它来自实际文件通过重定向。

    所以,只要去掉 | 就可以了。

    【讨论】:

    • 对不起,我应该使用 grep 以外的其他命令。对于 any 命令,我想要发生的是 1)不使用任何引用“文件”或“事物”的参数,以及 2)由于我正在编写的内容,我实际上需要能够只是写$ | command1 | command2 | command 3 | command 4而不引用$THATF。
    • @haakonstorm:许多命令默认读取标准输入——grep 如你所知,还有sedawksortcatuniq、@987654338 @(一种特殊情况;它只读取标准输入),... 对于许多类似过滤器的命令,默认行为是“读取命名文件(如果有);否则,读取标准输入'。多年来,这已被证明是一种合理的设计。
    • @JonathanLeffler stdin 上没有可阅读的内容。如上所述,我将开始我的命令以管道作为第一个字符。如$ |command2,并让上一个命令的输出通过管道传输(通过cat 或进程替换)。在 Mac 上可以使用 iTerm 中的热键来获取上一个命令的输出。
    • @haakonstorm:好的——如果你幸运的话,zsh 定义了它的含义(以| 开始一个命令)。如果你不走运,zsh 并没有定义它的含义。我知道没有其他外壳可以定义它的含义。所有正统的 shell 都期望管道作为两个命令之间的分隔符(连接器),而不是作为命令的一元前缀。如果做不到这一点,您将不得不编写自己的外壳来为您想要编写的内容赋予意义。我不确定您为什么要编写这样的代码。但是,这不是我的主要关注点。你可以随心所欲地选择。
    • 你能发布你的解决方案吗?
    【解决方案2】:

    回答我自己的问题。

    显示在命令开头单独使用 | 的 GIF 动画会自动替换为上一个命令的输出:

    编辑 ~/.zshrc 以覆盖 zsh 的 zle accept-line 小部件

    将以下内容附加到~/ .zshrc

    
    readonly THATF="path/to/your/temporary/file"
    
    my-accept-line () {  
      if [[ "${BUFFER:0:1}" == '|' ]]; then    
        /usr/local/bin/cliclick kd:shift,cmd t:a ku:shift w:100 t:c ku:cmd
        pbpaste>"${THATF}"
        BUFFER='cat ${THATF} '${BUFFER}
      fi  
      zle .accept-line
    }
    
    zle -N accept-line my-accept-line
    

    说明

    • 当您在输入命令后点击enter 时,zsh 会运行accept-line 小部件。
    • 我们覆盖了那个小部件,但在退出之前我们记得用zle .accept-line 调用原始小部件。使用点前缀运行工厂小部件。
    • iTerm2 中,shift+cmd+a 选择上一个命令的所有输出,cmd+c 将其复制到系统粘贴板。
    • 我们粘贴粘贴板的内容并将其重定向到之前声明的临时文件,由 ${THATF} 指向。
    • 我们将 $BUFFER(zsh 代码中的 zsh 特殊变量)添加到上一个命令的输出中。

    奖金

    • 我已将各种 fn-key 组合重新映射为我在 shell 中经常使用的表情符号和 unicode 符号。
    • fn+ctrl+arrow down 键入⏬符号;当作为 shell 命令的一部分输入并调用 zle accept-line 小部件时,将替换为您捕获的最后一个命令的输出的 第一行
    BUFFER=${BUFFER//⏬/$(cat ${THAT1F})}
    

    在我的实现中,${THAT1F) 被声明和填充如上,只是通过sed 进行过滤以过滤掉并且只抓取流中最先出现的 \NUL 或 \n 的部分。

    依赖关系,注意事项:

    这个特定的解决方案取决于:

    • cliclick 调度 macOS 键盘事件。也许存在原生解决方案,例如ANSI/转义序列。
    • iTerm 处理用于复制最后命令输出的键绑定。
    • zsh 用于 zle 小部件可配置性。

    另外,我必须提到,上面的代码 sn-p 是简单的、概念验证的、最小的。如果您要实施类似的事情,请采取措施确保安全性和健全性。一个开始的地方是不覆盖 accept-line 小部件,而是覆盖其他小部件之一与键绑定,以便 1)您可以事先查看和编辑修改后的命令,以及 2)您必须按 enter 接受您的修改命令。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-16
      • 2013-11-24
      • 1970-01-01
      相关资源
      最近更新 更多