如何区分两个命令的输出?

Ter*_*ary 230 command-line diff

我曾想象比较两个相似目录的内容的最简单方法是

diff `ls old` `ls new`
Run Code Online (Sandbox Code Playgroud)

但我明白为什么这不起作用;diff在命令行上收到一长串文件,而不是我希望的两个流。如何将两个输出直接传递给 diff?

Gil*_*il' 333

命令替换`…`将命令的输出替换到命令行中,因此diff将两个目录中的文件列表视为参数。您想要的是diff在其命令行上看到两个文件名,并将这些文件的内容作为目录列表。这就是进程替换的作用。

diff <(ls old) <(ls new)
Run Code Online (Sandbox Code Playgroud)

的参数diff看起来像/dev/fd/3/dev/fd/4:它们是对应于 bash 创建的两个管道的文件描述符。当diff打开这些文件时,它将连接到每个管道的读取端。每个管道的写入端都连接到ls命令。

  • `echo &lt;(echo) &lt;(echo)` 从未想过这会如此有趣 :D (65认同)
  • 进程替换 [并非所有 shell 都支持](http://mywiki.wooledge.org/ProcessSubstitution#Portability),但管道重定向是一种 [巧妙的解决方法](https://unix.stackexchange.com/a/11734/ 191235)。 (4认同)
  • 只是提一下,不建议解析 ls https://unix.stackexchange.com/questions/128985/why-not-parse-ls (2认同)

Woo*_*Yek 10

鱼壳

在 Fish shell 中,您必须通过管道输入psub。以下是使用Beyond Compare 比较heroku 和 dokku 配置的示例:

bcompare (ssh me@myapp.pl dokku config myapp | sort | psub) (heroku config -a myapp | sort | psub)
Run Code Online (Sandbox Code Playgroud)

  • 另一个图形差异工具是 `meld`,它是开源的,可在 Ubuntu 和 EPEL 存储库中使用。http://meldmerge.org/ (2认同)

hta*_*ess 7

我经常使用已接受答案中描述的技术:

diff <(ls old) <(ls new)
Run Code Online (Sandbox Code Playgroud)

但我发现我通常将它与比上面的示例复杂得多的命令一起使用。在这种情况下,制作 diff 命令可能会很烦人。我提出了一些其他人可能会觉得有用的解决方案。

我发现 99% 的情况下我会在运行 diff 之前尝试相关命令。因此,我想要比较的命令就在我的历史记录中......为什么不使用它们呢?

我使用内置的 Fix Command (fc) bash 来执行最后两个命令:

$ echo A
A
$ echo B
B
$ diff --color <( $(fc -ln -1 -1) ) <( $(fc -ln -2 -2 ) )
1c1
< B
---
> A
Run Code Online (Sandbox Code Playgroud)

fc 标志是:

-n:没有数字。它在列出时抑制命令编号。

-l:列表:命令在标准输出上列出。

-1 -1历史记录中的开始和结束位置,在本例中是从最后一个命令到最后一个命令,仅生成最后一个命令。

最后,我们将其包装起来$()以在子 shell 中执行命令。

显然,输入起来有点麻烦,所以我们可以创建一个别名:

alias dl='diff --color <( $(fc -ln -1 -1) ) <( $(fc -ln -2 -2 ) )'
Run Code Online (Sandbox Code Playgroud)

或者我们可以创建一个函数:

dl() {
    if [[ -z "$1" ]]; then
        first="1"
    else
        first="$1"
    fi
    if [[ -z "$2" ]]; then
        last="2"
    else
        last="$2"
    fi
    # shellcheck disable=SC2091
    diff --color <( $(fc -ln "-$first" "-$first") ) <( $(fc -ln "-$last" "-$last") )
}
Run Code Online (Sandbox Code Playgroud)

它支持指定要使用的历史行。使用两者后,我发现别名是我更喜欢的版本。


Ash*_*dal 6

对于 zsh, using 会=(command)自动创建一个临时文件并替换=(command)为文件本身的路径。使用命令替换,$(command)替换为命令的输出

所以有以下三种选择:

  1. 命令替换: $(...)
  2. 过程替换: <(...)
  3. zsh-风味过程替代: =(...)

zsh 风格的进程替代,#3,非常有用,可以像这样使用 diff 工具比较两个命令的输出,例如 Beyond Compare:

bcomp  =(ulimit -Sa | sort) =(ulimit -Ha | sort)
Run Code Online (Sandbox Code Playgroud)

对于 Beyond Compare,请注意您必须使用bcompfor 上面(而不是bcompare),因为bcomp启动比较并等待它完成。如果使用bcompare,则会启动比较并立即退出,因此创建的用于存储命令输出的临时文件消失了。

在此处阅读更多信息:http: //zsh.sourceforge.net/Intro/intro_7.html

还要注意这一点:

请注意,shell 创建了一个临时文件,并在命令完成后将其删除。

以下是zsh支持的两种进程替换类型之间的区别(即#2和#3):

如果您阅读 zsh 的手册页,您可能会注意到 <(...) 是另一种类似于 =(...) 的进程替换形式。两者之间有一个重要的区别。在 <(...) 情况下,shell 创建命名管道 (FIFO) 而不是文件。这样更好,因为它不会填满文件系统;但它并不适用于所有情况。事实上,如果我们在上面的例子中用 <(...) 替换 =(...),除了 fgrep -f <(...) 之外,所有这些都会停止工作。您不能编辑管道,也不能将其作为邮件文件夹打开;但是,fgrep 从管道中读取单词列表没有问题。您可能想知道为什么 diff <(foo) bar 不起作用,因为 foo | diff - 酒吧作品;这是因为如果 diff 注意到其参数之一是 - ,则会创建一个临时文件,然后将其标准输入复制到临时文件。

参考:https : //unix.stackexchange.com/questions/393349/difference-between-subshel​​ls-and-process-substitution

  • `$(...)` 不是进程替换,而是 *command* 替换。`&lt;(...)` 是进程替换。这就是为什么引用的段落根本没有提到`$(...)`。 (4认同)