Bash中的字符串差异


110

我试图找到一种方法来确定脚本中两个字符串之间的差异。我可以轻松地用diff或comm做到这一点,但是我不处理文件,我更不想将它们输出到文件中,进行比较并读回。

我看到comm,diff,cmp都允许传递两个文件或一个文件和标准输入-我想如果我不想输出两个文件就很好了...但是还是有点糟。

我一直在思考我可以使用grep或正则表达式-但我猜不是。


1
您实际上想做什么?

您可以对IFS更改使用子字符串操作和内置测试操作进行比较,但是您需要知道是否要逐个字符,逐个单词,逐行比较,忽略空白...
technosaurus

Answers:


198

使用diffcom或您想要的任何东西:

diff  <(echo "$string1" ) <(echo "$string2")

Greg的Bash常见问题:流程替代

或使用命名管道

mkfifo ./p
diff - p <<< "$string1" & echo "$string2" > p

Greg的Bash常见问题:使用命名管道

命名管道也称为FIFO。

-自身为标准输入。

<<< 是“此处字符串”。

&就像;但将其放在背景中


5
+1为正确答案。+1可以很好地解释符号。此外,格雷格的Bash常见问题解答已移至:mywiki.wooledge.org以上页面的链接现在位于mywiki.wooledge.org/ProcessSubstitutionmywiki.wooledge.org/BashFAQ/085
timemachine3030 2013年

谢谢!并且还将显示动态文件描述符FUNC(){ echo "$@"; "$@"; }; FUNC diff <(echo a) <(echo b);
Aquarius Power

我一直在寻找补偿两个阴影的方法。不知道是否有更优雅的方法可以做到这一点,但它确实有效。
fuma

如果$ string1和$ string2中有多行,并且diff输出添加或减去的行,这似乎可行。如果字符串是单行,并且line和两个字符串之间有一些区别怎么办?
alpha_989 '17

@ alpha_989,这是您的答案:$ diff <(echo "Here are the letters in String One.") <(echo "Here are the characters in String Two.") \n 1c1 \n < Here are the letters in String One. \n --- \n > Here are the characters in String Two. \n使用管道的方法类似,不同之处在于它显示进程号,1c1在下一个之后以开头$,然后等到您按<kbd> Enter <kbd>(或者您可以执行其他命令...)。
bballdave025

19

让我想起了这个问题:如何在Bash中区分两个管道?

如果您正在进行bash会话,则可以执行以下操作:

diff <cmd1 <cmd2
diff <(foo | bar) <(baz | quux)

通过<创建匿名命名管道-由bash管理-可以自动创建和销毁它们,与临时文件不同。

因此,如果您设法将两个不同的字符串作为命令的一部分(grep,awk,sed等)隔离,则可以执行以下操作:

diff < grep string1 myFile < grep string2 myFile

(如果您假设文件行中有string1=very_complicated_value和,例如string2=another_long_and_complicated_value':,而又不知道文件的内部格式,则我不建议您使用精确的命令)


13

我更喜欢cmpbash的Process Substitution功能:

$ cmp -bl <(echo -n abcda) <(echo -n aqcde)
  2 142 b    161 q
  5 141 a    145 e

说到位置2,第一个出现ab,第二个出现aq。在位置5,另一个差异正在发生。只需将这些字符串替换为变量,就可以完成。


仅在字符串长度相同时才有效!
strpeter '16

11

说你有三个弦

a="this is a line"
b="this is"
c="a line"

从a删除前缀b

echo ${a#"$b"}  # a line

从a中删除后缀c

echo ${a%"$c"}  # this is

2
我想这是最有效的方法。效果很好。但是,该语法有点难以掌握。
Mikael Roos 2014年

@MikaelRoos同意。更容易阅读(无论如何对我而言)将是使用sed :(echo "$a" | sed "s!^$b!!g" 我将标准sed分隔符/换成!,以防要处理的变量是路径。此外,您可以使用here字符串代替echo:sed ... <<< $a。)
ACK_stoverflow

0

另一个例子:

before="184613 102050 83756 63054"
after="184613 102050 84192 83756 63054"

comm -23 <(tr ' ' $'\n' <<< $after | sort) <(tr ' ' $'\n' <<< $before | sort)

产出

84192

原始答案在这里

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.