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

diff `ls old` `ls new`


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

评论

相关:如何比较两个unix命令的输出以找出差异?,区分两个程序的输出而没有临时文件

#1 楼

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

diff <(ls old) <(ls new)


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

评论


echo <(echo)<(echo)从来没有想过这可能会很有趣:D

–水瓶座力量
2014年12月13日在1:46

并非所有shell都支持进程替换,但是管道重定向是一个很好的解决方法。

– Irfan434
17年9月16日在14:38

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

–卡图
18年4月12日在7:59

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

–吉尔斯'所以-不再是邪恶的'
18年4月12日在11:03

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

–吉尔斯'所以-不再是邪恶的'
19年8月28日在11:33

#2 楼

鱼壳

在鱼壳中,您必须将其放入psub中。以下是使用Beyond Compare比较heroku和dokku配置的示例:

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


评论


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

– phiphi
18年6月18日在7:36

#3 楼

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

因此有三个选项:


命令替换:$(...)
过程替换:<(...)

zsh-Flavored Process Substitution:=(...)


zsh调味工艺替代品#3非常有用,可以像这样用来比较输出使用diff工具的两个命令,例如Beyond Compare:启动比较并等待其完成。如果使用bcomp,则会启动比较并立即退出,因此,用于存储命令输出的临时文件将消失。

此处更多内容:http://zsh.sourceforge.net/Intro /intro_7.html

也请注意:


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

以下是zsh支持的两种类型的Process替换之间的区别(即#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

评论


$(...)不是进程替换,而是命令替换。 <(...)是进程替换。这就是为什么引用的段落根本没有提到$(...)。

–muru
18-6-29在9:10



#4 楼

我经常使用公认的答案中所述的技术:
diff <(ls old) <(ls new)

,但我发现我通常使用比上面示例更复杂的命令来使用它。在这种情况下,制作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

fc标志是:

-n:无数字。
-l:列出:命令在标准输出上列出。

-1 -1引用历史记录中的开始和结束位置,在这种情况下它从最后一个命令到最后一个仅产生最后一个命令的命令。
最后,我们将其包装在$()中以在子shell中执行该命令。可以创建一个别名:
alias dl='diff --color <( $(fc -ln -1 -1) ) <( $(fc -ln -2 -2 ) )'

,或者我们可以创建一个函数:
dl() {
    if [[ -z "" ]]; then
        first="1"
    else
        first=""
    fi
    if [[ -z "" ]]; then
        last="2"
    else
        last=""
    fi
    # shellcheck disable=SC2091
    diff --color <( $(fc -ln "-$first" "-$first") ) <( $(fc -ln "-$last" "-$last") )
}

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