AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / ubuntu / 问题 / 1255005
Accepted
Zorglub29
Zorglub29
Asked: 2020-06-30 23:19:32 +0800 CST2020-06-30 23:19:32 +0800 CST 2020-06-30 23:19:32 +0800 CST

Bash 函数可将终端输出稳健地通过管道传输到 vim

  • 772

我经常以这种方式将我的终端输出重定向到 vim,我厌倦了一直打字:

ls | vim -

我想定义一个函数v来为我做这件事,即我希望能够输入:

v ls并且这以某种方式“扩展”到上一个命令。

我可以使用这种脚本在简单的情况下执行此操作(当然,这可以重构为一个小函数):

#!/bin/bash 
 
touch crrt_cmd

while (( "$#" )); do 
  echo -n $1 >> crrt_cmd
  echo -n " " >> crrt_cmd
  shift 
done

chmod +x crrt_cmd
bash crrt_cmd | vim -

rm crrt_cmd

这适用于非常简单的命令,例如lsor ls -l,但是当某些管道存在时,它根本不起作用。

关于如何执行类似操作的任何想法,但适用于任何有效的 bash 命令?


所以为了清楚起见,如果可能的话,我希望事情以这种方式工作:

v ls | grep keyword | head -5

将转化为:

ls | grep keyword | head -5 | vim -
vim command-line bash pipe
  • 2 2 个回答
  • 1527 Views

2 个回答

  • Voted
  1. Best Answer
    Eliah Kagan
    2020-06-30T23:25:48+08:002020-06-30T23:25:48+08:00

    进程替换可能会提供最接近您想要的语法。

    这可行,并且可能符合您的喜好:

    vim <(cmd1 | cmd2 | ...)
    

    这使您可以将整个命令的文本放在一起,并将其放在发送它的命令之后(而不是之前)vim,这似乎是您的主要目标。没有-争论是故意的。

    您不需要为此定义函数或别名,但当然您可以通过定义为别名或函数vim来缩短:vv

    alias v=vim
    
    v() { vim "$@"; }
    

    v <(cmd1 | cmd2 | ...)比 . 多一个字符v 'cmd1 | cmd2 | ...'。但它也避免了muru 警告的引用地狱。', ", 和\可以出现在里面<( ),它们以通常的方式工作。这也可以很好地嵌套:您可以在命令中使用其他括号,只要它们的使用方式在语法上是正确的。

    这是过程替换。Bash 创建了一个可以通过类似路径访问的管道/dev/fd/63(不要与命令本身所涉及的管道混淆)。它用那个管道的路径代替<(cmd1 | cmd2 | ...),所以vim看到一个像/dev/fd/63. 您的命令 ,cmd1 | cmd2 | ...在子 shell 中异步运行,其输出被发送到vim读取的管道。(这就是为什么你不写-:vim从/dev/fd/63或最终被调用的任何内容中读取,而不是从标准输入中读取。)

    muru指出,您可以编写一个扩展为的别名vim <(:

    alias v='vim <('
    

    您可以将此别名定义~/.bash_aliases放在~/.bashrc.

    这让你更接近你最初想要的语法——你只需要)在你的命令末尾写一个:

    v cmd1 | cmd2 | cmd3)
    

    进程替换还有一个额外的好处是你可以多次使用它,<( )在同一个命令中编写多个结构,以防你想分别运行多个命令并在单独的vim缓冲区中查看它们的输出。

    vim <(cmd1 | cmd2 | cmd3) <(cmd4 <infile) <(FOO=bar cmd5) <(cmd6 | cmd7)
    

    当然,正如 muru 所说,对于运行管道并在 中打开其输出的用例,后缀操作仍然更简单vim,因为您只需要vim在管道末尾添加另一个命令 for。

    感谢muru提供的洞察力,v可以为vim <(.


    最简单的案例:更好的方式来实现你的原始v

    vim <( ),上面详述,即使在最简单的情况下也可以使用。但是,当您不编写包含两个或多个命令的管道cmd1 | cmd2(所以你可能仍然想要一个函数来完成你原来的功能。cmd <infileFOO=bar cmdv

    您的实现运行一个循环来连接参数的文本。这很复杂,并且在大多数涉及引用的情况下也会中断,即使您修复$1以"$1"防止初始拆分和globbing也是如此。在v 'foo bar'中,您的v函数(与任何函数一样)不会收到任何引号:它看到foo bar. 没关系,因为它作为单个参数接收它......直到它构造一个包含它的脚本并运行该脚本,此时foo bar被解析为两个单词,这成为两个参数。

    幸运的是,有一种更可靠的方法,也更简单、更短。"$@"扩展为传递给当前函数或当前脚本(如果不在函数中)的所有参数。单独的论点既不会进一步分裂,也不会相互结合。所以你只需要:

    v() { "$@" | vim -; }
    

    (当然,如果您要定义v做其他事情——也许是vim <(如上所述的别名——那么您可能会想把它称为其他事情,也许u。)

    运行该命令定义了一个 shell 函数v,该函数运行在其第一个参数中命名的命令并传递其后续参数。这不会构造一个单独的脚本,也不会使用bash -cor eval。所以它不会有错误地拆分或连接参数的风险,因为参数永远不会被拆分或连接:它们是分开进入函数的,并"$@"单独使用它们。

    您可以将其放在末尾,~/.bashrc以便为您的交互式 shell 定义它。

    或者,如果您更喜欢它是一个脚本,则使用以下内容创建一个名为v(或任何您想要的命令名称)的文件:

    #!/bin/bash
    "$@" | vim -
    

    标记文件可执行文件 ( chmod +x v) 并将其放在$PATH. 我建议,如果它存在,它会在您登录时~/bin自动添加到您的帐户中(除非您已更改为不这样做)。$PATH~/.profile

    • 14
  2. muru
    2020-07-01T00:15:48+08:002020-07-01T00:15:48+08:00

    函数不能对 bash 中的任意非简单命令执行此操作,因为函数本身就是一个简单命令——当函数定义开始起作用时,为时已晚。别名的扩展可以包含管道,因此您可以在别名中添加 piplines,但当然只能在命令的开头:

    $ alias e='echo foo |'
    $ e grep bar  # expands to echo foo | grep bar
    

    如果您要选择将不可避免地遵循以下内容的精神错乱:

    v () { eval "$@" | vim -; }
    # v 'ls -l | nc' 
    

    你迟早会引用地狱的话。

    去后缀操作,它更简单。


    精神错乱的其他选择:

    zsh 中的全局别名

    您可以在 zsh 的命令行中的任何位置(而不仅仅是开头)展开别名:

    % alias -g v='| vim -'
    % echo foo | grep foo v
    Vim: Reading from stdin...
    
    • 6

相关问题

  • 如何从命令行刻录双层 dvd iso

  • 如何从命令行判断机器是否需要重新启动?

  • 文件权限如何工作?文件权限用户和组

  • 如何在 Vim 中启用全彩支持?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何运行 .sh 脚本?

    • 16 个回答
  • Marko Smith

    如何安装 .tar.gz(或 .tar.bz2)文件?

    • 14 个回答
  • Marko Smith

    如何列出所有已安装的软件包

    • 24 个回答
  • Marko Smith

    无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗?

    • 25 个回答
  • Martin Hope
    Flimm 如何在没有 sudo 的情况下使用 docker? 2014-06-07 00:17:43 +0800 CST
  • Martin Hope
    Ivan 如何列出所有已安装的软件包 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    La Ode Adam Saputra 无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗? 2010-11-30 18:12:48 +0800 CST
  • Martin Hope
    David Barry 如何从命令行确定目录(文件夹)的总大小? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher “以下软件包已被保留:”为什么以及如何解决? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford 如何删除 PPA? 2010-07-30 01:09:42 +0800 CST

热门标签

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve