Как узнать, является ли текстовый файл подмножеством другого


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

Ответы:


11

Если это содержимое файла называются file1, file2и file3в порядке apearance , то вы можете сделать это с помощью следующего однострочника:

 # 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

Добро пожаловать, конечно, есть и другие решения с более специфичными для Unix инструментами. Но это кажется хорошим использованием inоператора Python .
Тимо

Существует оболочка для командной строки python, которая делает его более похожим на unix, со встроенным конвейером, называемым pyp: code.google.com/p/pyp. Я думаю, тривиально сделать это решение более unix-подобным инструменту с одним вкладышем.
августа

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 (максимальное значение байта), это означает, что разделителя нет, это эквивалентно действию $/ = undef. В этом случае <>возвращает полное содержимое одного файла, это режим slurp .

После того, как мы имеем содержание файлов в двух $hи $nпеременных, мы можем использовать , index()чтобы определить , если один находится в другом.

Это означает, однако, что все файлы хранятся в памяти, что означает, что метод не будет работать для очень больших файлов.

Для файлов mmappable (обычно включает обычные файлы и наиболее доступные для поиска файлы, например блочные устройства), которые можно обойти, используя mmap()файлы, как в Sys::Mmapмодуле perl:

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.txtи b.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

Если один подмножество другого возвращения сценария 0для Trueиначе 1.


Что делает% L? Этот скрипт, похоже, не работает, и я пытаюсь его отладить ...
Алекс

Я на самом деле не помню значение %L, это было три года назад. С man diff(текущая версия) %Lозначает «содержимое строки».
gc5

% L печатает содержимое «новой» строки. IOW, не печатайте ничего для неизмененных или старых строк, но печатайте содержимое строки для новых строк.
PLG

Этот скрипт работает для меня, из коробки!
PLG

2

Если f1 является подмножеством f2, то f1 - f2 - пустое множество. Основываясь на этом, мы можем написать функцию is_subset и функцию, полученную из нее. В соответствии с разницей между двумя текстовыми файлами


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
  cat "$ 1.sorted" "$ 2.sorted" "$ 2.sorted" | сортировать | uniq -u
  remove_sorted_files $ 1 $ 2
}

rset_diff () {
  sort_files $ 1 $ 2
  cat "$ 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

  if [-z $ output]; тогда
    вернуть 0
  еще
    возврат 1
  фи

}


Должен ли этот скрипт начинаться с #!/bin/bash?
Алекс

2

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

Comm сравнивает два отсортированных файла построчно. Он может быть запущен таким образом, что выводит строки, которые появляются только в первом указанном файле. Если первый файл является подмножеством второго, то все строки в 1-м файле также появляются во 2-м, поэтому вывод не производится:

$ comm -23 <(sort subset | uniq) <(sort set | uniq) | head -1
# comm returns no output if subset ⊆ set
# comm outputs something if subset ⊊ set
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.