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


Answers:


246

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

diff <(ls old) <(ls new)

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


49
echo <(echo) <(echo)从来没有想过这可能会如此有趣:D
水瓶座力量

3
并非所有Shell都支持进程替换,但是管道重定向是一种巧妙的解决方法
Irfan434

1
只需提一下,不建议解析ls unix.stackexchange.com/questions/128985/why-not-parse-ls
Katu

@Katu的问题ls是它会处理文件名。解析其输出很脆弱(不适用于“怪异”文件名)。对于比较两个目录列表,只要输出是明确的就可以。对于任意文件名,这将需要一个选项,例如--quoting-style=escape
吉尔斯

1
@will <(…)创建一个管道。似乎meld不适用于管道,因此您不能使用<(…)。在zsh中,您可以替换<(…)=(…)并且它将起作用,因为=(…)将中间输出放置在临时文件中。在bash中,我认为没有任何方便的语法,您必须自己管理临时文件。
吉尔斯

3

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

因此,有三种选择:

  1. 命令替换: $(...)
  2. 流程替代: <(...)
  3. zsh-Flavored流程替代: =(...)

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

bcomp  =(ulimit -Sa | sort) =(ulimit -Ha | sort)

对于“超越比较”,请注意,由于启动了比较并等待其完成,因此您必须使用bcomp以上(而不是bcompare)。如果使用,则会启动比较并立即退出,因此,用于存储命令输出的临时文件将消失。bcompbcompare

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

另请注意:

请注意,外壳程序会创建一个临时文件,并在命令完成后将其删除。

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

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

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


2
$(...)不是进程替代,而是命令替代。<(...)是流程替代。这就是为什么引用的段落根本没有提及$(...)
大师

2

鱼壳

在Fish shell中,您必须将其放入psub中。这是一个用Beyond Compare比较 heroku和dokku配置的示例:

bcompare (ssh me@myapp.pl dokku config myapp | sort | psub) (heroku config -a myapp | sort | psub)

1
另一个图形化差异工具是meld开源的,可在Ubuntu和EPEL存储库中使用。meldmerge.org
phiphi,

0

我经常使用公认的答案中描述的技术:

diff <(ls old) <(ls new)

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

我发现在运行diff之前,我有99%的时间尝试了相关命令。因此,我想比较的命令就在我的历史中……为什么不使用它们呢?

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

$ echo A
A
$ echo B
B
$ diff --color <( $(fc -ln -1 -1) ) <( $(fc -ln -2 -2 ) )
1c1
< B
---
> A

fc标志是:

-n:没有数字。列出时禁止显示命令编号。

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

-1 -1指开始和结束在:放置的历史,到产生最后那个命令的最后一个命令这种情况下它从最后的命令。

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

显然,这有点麻烦,所以我们可以创建一个别名:

alias dl='diff --color <( $(fc -ln -1 -1) ) <( $(fc -ln -2 -2 ) )'

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

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") )
}

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.