Cara mengetahui apakah file teks adalah bagian dari yang lain

12

Saya mencoba menemukan cara untuk menentukan apakah file teks adalah bagian dari yang lain ..

Sebagai contoh:

foo
bar

adalah bagian dari

foo
bar
pluto

Sementara:

foo
pluto

dan

foo
bar

bukan bagian dari satu sama lain ...

Apakah ada cara untuk melakukan ini dengan perintah?

Pemeriksaan ini harus berupa pemeriksaan silang, dan harus dikembalikan:

file1 subset of file2 :    True
file2 subset of file1 :    True
otherwise             :    False
gc5
sumber
Solusi yang berpotensi lebih efisien (jika file juga dipesan): github.com/barrycarter/bcapps/blob/master/…
barrycarter

Jawaban:

11

Jika isi file tersebut dipanggil file1, file2dan file3dalam urutan penampilan maka Anda dapat melakukannya dengan satu-baris berikut:

 # 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
Timo
sumber
Terima kasih atas jawaban Anda .. +1 .. Saya tidak tahu apakah menerima jawaban saya karena jawaban Anda tidak spesifik unix-linux dan jawaban saya sedikit lebih cepat, sejauh saya mengujinya .. bagaimana menurut Anda?
gc5
Terima kasih, tentu saja ada solusi lain dengan alat khusus yang lebih unix. Tapi ini sepertinya penggunaan yang baik dari inoperator Python .
Timo
Ada pembungkus baris perintah python untuk membuatnya lebih unix like, dengan piping built in, bernama pyp: code.google.com/p/pyp Saya pikir ini sepele untuk membuat solusi ini lebih unix seperti alat liner satu.
IBr
3

Dengan 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

-0octalmendefinisikan pembatas rekaman. Ketika angka oktal lebih besar dari 0377 (nilai byte maksimum), itu berarti tidak ada pembatas, itu setara dengan melakukan $/ = undef. Dalam hal ini, <>mengembalikan konten lengkap dari satu file, itulah mode slurp .

Setelah kami memiliki konten file dalam dua $hdan $nvariabel, kita dapat menggunakan index()untuk menentukan apakah satu ditemukan di yang lain.

Namun itu berarti bahwa seluruh file disimpan dalam memori yang berarti metode itu tidak akan berfungsi untuk file yang sangat besar.

Untuk file mmappable (biasanya termasuk file biasa dan file yang paling dicari seperti perangkat blok), yang dapat dikerjakan dengan menggunakan mmap()pada file, seperti dengan Sys::Mmapmodul 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
Stéphane Chazelas
sumber
2

Saya menemukan solusi berkat pertanyaan ini

Pada dasarnya saya menguji dua file a.txtdan b.txtdengan skrip ini:

#!/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

Jika satu bagian dari yang lain skrip kembali 0untuk Truesebaliknya 1.

gc5
sumber
Apa yang dilakukan% L? Skrip ini sepertinya tidak berfungsi, dan saya mencoba untuk men-debug-nya ...
Alex
Sebenarnya saya tidak ingat artinya %L, itu tiga tahun lalu. Dari man diff(versi saat ini) %Lberarti "isi baris".
gc5
% L mencetak isi dari baris "baru". TKI, jangan cetak apa pun untuk garis yang tidak berubah atau garis lama, tetapi cetak konten garis untuk baris baru.
PLG
Skrip ini berfungsi untuk saya, di luar kotak!
PLG
2

Jika f1 adalah himpunan bagian dari f2 maka f1 - f2 adalah himpunan kosong. Berdasarkan itu kita dapat menulis fungsi is_subset dan fungsi yang diturunkan darinya. Sesuai Tetapkan perbedaan antara 2 file teks


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

  jika [! -f $ f1_sorted]; kemudian
    cat $ 1 | sortir | uniq> $ f1_sorted
  fi

  jika [! -f $ f2_sorted]; kemudian
    cat $ 2 | sortir | uniq> $ f2_sorted
  fi
}

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
  cat "$ 1.sorted" "$ 2.sorted" | sortir | uniq
  remove_sorted_files $ 1 $ 2
}

set_diff () {
  sort_files $ 1 $ 2
  cat "$ 1.sorted" "$ 2.sorted" "$ 2.sorted" | sortir | uniq -u
  remove_sorted_files $ 1 $ 2
}

rset_diff () {
  sort_files $ 1 $ 2
  cat "$ 1.sorted" "$ 2.sorted" "$ 1.sorted" | sortir | uniq -u
  remove_sorted_files $ 1 $ 2
}

is_subset () {
  sort_files $ 1 $ 2
  output = $ (set_diff $ 1 $ 2)
  remove_sorted_files $ 1 $ 2

  jika [-z $ output]; kemudian
    kembali 0
  lain
    kembali 1
  fi

}

Saurabh Hirani
sumber
Haruskah skrip ini dimulai dengan #!/bin/bash?
Alex
2

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

Comm membandingkan dua file yang disortir baris demi baris. Ini dapat dijalankan sedemikian rupa sehingga menghasilkan garis yang hanya muncul di file yang ditentukan pertama. Jika file pertama adalah subset dari yang kedua, maka semua baris dalam file 1 juga muncul di ke-2, sehingga tidak ada output yang dihasilkan:

$ comm -23 <(sort subset | uniq) <(sort set | uniq) | head -1
# comm returns no output if subset ⊆ set
# comm outputs something if subset ⊊ set
Alec
sumber