如何知道一个文本文件是否是另一个文件的子集


12

我试图找到一种方法来确定文本文件是否是另一个文件的子集。

例如:

foo
bar

是...的子集

foo
bar
pluto

而:

foo
pluto

foo
bar

不是彼此的子集...

有没有办法用命令来做到这一点?

此检查必须是交叉检查,并且必须返回:

file1 subset of file2 :    True
file2 subset of file1 :    True
otherwise             :    False

潜在的更有效的解决方案(如文件也订购):github.com/barrycarter/bcapps/blob/master/...
barrycarter

Answers:


11

如果这些文件的内容被称为file1file2并且file3按照出现的顺序被调用,则可以使用以下一种格式来实现:

 # python -c "x=open('file1').read(); y=open('file2').read(); print x in y or y in x"
 True
 # python -c "x=open('file2').read(); y=open('file1').read(); print x in y or y in x"
 True
 # python -c "x=open('file1').read(); y=open('file3').read(); print x in y or y in x"
 False

感谢您的回答.. +1 ..我不知道是否接受我的回答,因为您的回答不是特定于unix-linux,而据我测试,我的回答要快一些..您怎么看?
gc5 2014年

不客气,当然还有其他解决方案,其中包含更多针对Unix的特定工具。但这似乎很好地使用了Python的in运算符。
Timo 2014年

有一个python命令行包装程序可以使它更像unix,并且内置有管道,名为pyp:code.google.com/p/pyp我认为让这个解决方案像一个内衬工具一样更像unix是微不足道的。
IBr

3

perl

if perl -0777 -e '$n = <>; $h = <>; exit(index($h,$n)<0)' needle.txt haystack.txt
then echo needle.txt is found in haystack.txt
fi

-0octal定义记录定界符。当该八进制数大于0377(最大字节值)时,这意味着没有定界符,它等效于do $/ = undef。在这种情况下,<>返回单个文件的全部内容,即slurp模式

一旦我们将文件的内容分为两个变量$h$n变量,就可以index()用来确定在另一个变量中是否找到了一个。

但是,这意味着整个文件都存储在内存中,这意味着该方法不适用于非常大的文件。

对于mmappable文件(通常包括常规文件和大多数可搜索文件,例如块设备),可以通过mmap()在文件上使用来解决这些问题,例如与Sys::Mmapperl模块一起使用:

if 
  perl -MSys::Mmap -le '
    open N, "<", $ARGV[0] || die "$ARGV[0]: $!";
    open H, "<", $ARGV[1] || die "$ARGV[1]: $!";
    mmap($n, 0, PROT_READ, MAP_SHARED, N);
    mmap($h, 0, PROT_READ, MAP_SHARED, H);
    exit (index($h, $n) < 0)' needle.txt haystack.txt
then
  echo needle.txt is found in haystack.txt
fi

2

由于这个问题,我找到了解决方案

基本上,我正在测试两个文件a.txtb.txt使用此脚本:

#!/bin/bash

first_cmp=$(diff --unchanged-line-format= --old-line-format= --new-line-format='%L' "$1" "$2" | wc -l)
second_cmp=$(diff --unchanged-line-format= --old-line-format= --new-line-format='%L' "$2" "$1" | wc -l)

if [ "$first_cmp" -eq "0" -o "$second_cmp" -eq "0" ]
then
    echo "Subset"
    exit 0
else
    echo "Not subset"
    exit 1
fi

如果一个子集中的其它脚本回报0True,否则1


%L做什么?该脚本似乎无效,我正在尝试对其进行调试...
Alex

我实际上不记得%L三年前的含义。从man diff(当前版本)%L是指“行内容”。
gc5

%L打印“新”行的内容。IOW,不要为未更改的行或旧行打印任何内容,而为新行打印行的内容。
PLG

这个脚本对我有用,开箱即用!
PLG

2

如果f1是f2的子集,则f1-f2是一个空集。在此基础上,我们可以编写一个is_subset函数以及从中派生的函数。根据2个文本文件之间的设置差异


sort_files(){
  f1_sorted =“ $ 1.sorted”
  f2_sorted =“ $ 2.sorted”

  如果[!-f $ f1_sorted]; 然后
    猫$ 1 | 排序 uniq> $ f1_sorted
  科幻

  如果[!-f $ f2_sorted]; 然后
    猫$ 2 | 排序 uniq> $ f2_sorted
  科幻
}

remove_sorted_files(){
  f1_sorted =“ $ 1.sorted”
  f2_sorted =“ $ 2.sorted”
  rm -f $ f1_sorted
  rm -f $ f2_sorted
}

set_union(){
  sort_files $ 1 $ 2
  猫“ $ 1.sorted”“ $ 2.sorted” | 排序 优衣库
  remove_sorted_files $ 1 $ 2
}

set_diff(){
  sort_files $ 1 $ 2
  猫“ $ 1.sorted”“ $ 2.sorted”“ $ 2.sorted” | 排序 uniq -u
  remove_sorted_files $ 1 $ 2
}

rset_diff(){
  sort_files $ 1 $ 2
  猫“ $ 1.sorted”“ $ 2.sorted”“ $ 1.sorted” | 排序 uniq -u
  remove_sorted_files $ 1 $ 2
}

is_subset(){
  sort_files $ 1 $ 2
  输出= $(set_diff $ 1 $ 2)
  remove_sorted_files $ 1 $ 2

  如果[-z $ output]; 然后
    返回0
  其他
    返回1
  科幻

}


该脚本应以开头#!/bin/bash吗?
亚历克斯(Alex)

2

http://www.catonmat.net/blog/set-operations-in-unix-shell/中

Comm逐行比较两个排序的文件。它的运行方式可能是输出仅出现在第一个指定文件中的行。如果第一个文件是第二个文件的子集,那么第一个文件中的所有行也会出现在第二个文件中,因此不会产生任何输出:

$ comm -23 <(sort subset | uniq) <(sort set | uniq) | head -1
# comm returns no output if subset ⊆ set
# comm outputs something if subset ⊊ set
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.