অন্য ফাইলটিতে থাকা একটি ফাইল থেকে লাইনগুলি মোছা হচ্ছে


126

আমার একটি ফাইল রয়েছে f1:

line1
line2
line3
line4
..
..

আমি অন্য ফাইলটিতে থাকা সমস্ত লাইন মুছতে চাই f2:

line2
line8
..
..

আমি সঙ্গে কিছু চেষ্টা catএবং sed, যা ছিল না এমনকি আমি কি উদ্দেশ্যে পাসে। কিভাবে আমি এটি করতে পারব?



আপনি যদি অন্য কোনও ফাইল থেকে স্ট্রিং "এমনকি" অন্তর্ভুক্ত থাকা ফাইলগুলি থেকে লাইনগুলি সরিয়ে ফেলতে দেখছেন (উদাহরণস্বরূপ আংশিক মিলগুলি) unix.stackexchange.com
ক্র্যাশনস /

উত্তর:


154

grep -v -x -f f2 f1 কৌতুক করা উচিত।

ব্যাখ্যা:

  • -v মেলানো লাইনগুলি নির্বাচন করতে
  • -x শুধুমাত্র পুরো লাইন মেলে
  • -f f2 থেকে নিদর্শন পেতে f2

এক পরিবর্তে ব্যবহার করতে পারেন grep -Fবা fgrepমেলে সংশোধন স্ট্রিং থেকে f2বদলে নিদর্শন (যদি আপনি বরং এ লাইন চিকিত্সা চেয়ে একটি "তুমি কি দেখতে হলে কি আপনি পেতে" পদ্ধতিতে লাইন অপসারণ চান f2Regex নিদর্শন হিসাবে)।


22
এতে O (n²) জটিলতা রয়েছে এবং একবারে কয়েকটি কে-লাইন বেশি ফাইল যুক্ত হয়ে ফাইলগুলি শেষ হতে কয়েক ঘন্টা লাগতে শুরু করবে।
আরনৌদ লে ব্ল্যাঙ্ক

11
কোন SO প্রস্তাবিত আলগোরিথমগুলিতে O (n ^ 2) জটিলতা রয়েছে কেবলমাত্র O (n) জটিলতা রয়েছে তা নির্ধারণ করার পরেও প্রতিযোগিতায় কয়েক ঘন্টা সময় নিতে পারে।
HDave

2
আমি প্রতিটি প্রতি 2k লাইনের 2 টি ফাইলের জন্য এটি চেষ্টা করেছিলাম এবং এটি ওএসের হাতে মারা যায় (মঞ্জুর হয়েছে, এটি একটি অত শক্তিশালী ভিএম নয়, তবে এখনও)।
ট্রেবার রুড

1
আমি এর কমনীয়তা ভালবাসি; জোনা ক্রিস্টোফার সাহনওয়ালের উত্তরের গতি আমি পছন্দ করি।
অ্যালেক্স হল

1
@ arnaud576875: আপনি কি নিশ্চিত? এটি বাস্তবায়নের উপর নির্ভর করে grepf2অনুসন্ধানটি শুরুর আগে যদি এটি সঠিকভাবে প্রাক-প্রক্রিয়াজাত করে তবে অনুসন্ধানে কেবল ও (এন) সময় লাগবে।
হ্যালো গুডবাই

57

পরিবর্তে কম চেষ্টা করুন (ধরে নেওয়া f1 এবং f2 "ইতিমধ্যে সাজানো")

comm -2 -3 f1 f2

5
আমি নিশ্চিত নই commযে সমাধানটির প্রশ্নের প্রশ্নটি ইঙ্গিত করে না যে রেখাগুলি f1যেগুলি সাজানো হয়েছে তা ব্যবহারের পূর্বশর্তcomm
gabuzo

1
এটি আমার পক্ষে কাজ করেছিল, যেহেতু আমার ফাইলগুলি বাছাই করা হয়েছিল এবং সেগুলির একটিতে 250,000+ লাইন ছিল, অন্যটিতে কেবল 28,000 lines ধন্যবাদ!
শীতের

1
যখন এটি কাজ করে (ইনপুট ফাইলগুলি বাছাই করা হয়), এটি অত্যন্ত দ্রুত!
মাইক জারভিস

Arnaud576875 এর সমাধান হিসাবে, আমার জন্য সাইগউইন ব্যবহার করার জন্য, এটি দ্বিতীয় ফাইলটিতে ডুপ্লিকেট লাইনগুলি মুছে ফেলা হতে পারে যা রাখা যেতে পারে।
অ্যালেক্স হল

9
আপনি প্রথমে ফাইলগুলি বাছাই করতে প্রক্রিয়া বিকল্প ব্যবহার করতে পারেন, অবশ্যই:comm -2 -3 <(sort f1) <(sort f2)
ডেভেমাইরন

14

অতিরিক্ত ফাইল নয় এমন ফাইলগুলি বাদ দেওয়ার জন্য আপনি AWK এর এসোসিয়েটিভ অ্যারে ব্যবহার করতে পারেন।

awk 'NR == FNR { list[tolower($0)]=1; next } { if (! list[tolower($0)]) print }' exclude-these.txt from-this.txt 

আউটপুট "ক্রমে-টেক্সট" ফাইলের মতো একই ক্রমে থাকবে। tolower()যদি আপনি যে প্রয়োজন ফাংশন, এটা কেস-অবশ করে তোলে।

অ্যালগরিদমিক জটিলতা সম্ভবত ও (এন) (বাদ-এই.txt আকার) + ও (এন) (এই-টেক্সট আকার থেকে) হবে


আপনি যে ফাইলগুলি খুব বিশাল না বলে কেন? ভয়টি এখানে (আমি ধরে নিই) হ্যাশ তৈরির জন্য সিস্টেম মেমরি থেকে দূরে থাকা সিস্টেমটি চালিয়ে যাচ্ছে, বা অন্য কোনও সীমাবদ্ধতা রয়েছে?
রজারডপ্যাক

অনুসারীদের জন্য, লাইনগুলিকে "স্যানিটাইজ" করার আরও আরও আক্রমণাত্মক বিকল্প রয়েছে (যেহেতু তুলনাটি এসোসিয়েটিভ অ্যারে ব্যবহার করার জন্য সঠিক হতে হবে), প্রাক্তন ইউনিক্স.স্ট্যাকেক্সেঞ্জাও
১45১13১২ /

@ আরগারডপ্যাক: একটি বড় বর্জনকারী ফাইলের জন্য একটি বড় হ্যাশ অ্যারের প্রয়োজন হবে (এবং একটি দীর্ঘ প্রক্রিয়াজাতকরণের সময়)। একটি বৃহত "এই-টেক্সট" এর জন্য কেবল দীর্ঘ প্রক্রিয়াজাতকরণের প্রয়োজন হবে।
পরবর্তী বিজ্ঞপ্তি না দেওয়া পর্যন্ত বিরতি দেওয়া হয়েছে।

1
exclude-these.txtখালি থাকলে এটি ব্যর্থ হয় (অর্থাত্ কোনও আউটপুট উত্পাদন করে না) । @ জোনা-ক্রিস্টোফার-সাহ্নওয়াল্টের উত্তর নীচে এই ক্ষেত্রে কাজ করে। আপনি একাধিক ফাইলও নির্দিষ্ট করতে পারেন যেমনawk '{if (f==1) { r[$0] } else if (! ($0 in r)) { print $0 } } ' f=1 done.out failed.out f=2 all-files.out
গ্রাহাম রাসেল

11

ডেনিস উইলিয়ামসনের উত্তরের মতো (বেশিরভাগ সিন্ট্যাকটিক পরিবর্তন, উদাহরণস্বরূপ কৌশলটির পরিবর্তে ফাইল নম্বর সেট করা NR == FNR):

awk '{if (f==1) { r[$0] } else if (! ($0 in r)) { print $0 } } ' f=1 exclude-these.txt f=2 from-this.txt

অ্যাক্সেস r[$0]সেই লাইনের জন্য এন্ট্রি তৈরি করে, কোনও মান সেট করার দরকার নেই।

ধরে নেওয়া যায় যে ধ্রুবক ধ্রুবক অনুসন্ধান এবং (গড়) ধ্রুবক আপডেটের সময় সহ একটি হ্যাশ টেবিল ব্যবহার করে, এর সময় জটিলতা হবে ও (এন + এম), যেখানে এন এবং এম ফাইলগুলির দৈর্ঘ্য। আমার ক্ষেত্রে, এনটি ছিল 25 মিলিয়ন ডলার এবং এম ~ 14000। অজানা সমাধানটি বাছাইয়ের চেয়ে অনেক দ্রুত ছিল এবং আমিও মূল ক্রমটি রাখা পছন্দ করি।


এটি ডেনিস উইলিয়ামসনের উত্তর থেকে কীভাবে আলাদা? কেবলমাত্র পার্থক্য যে এটি হ্যাশটিতে একটি অ্যাসাইনমেন্ট না করে, এর চেয়ে কিছুটা দ্রুত? অ্যালগরিদমিক জটিলতা কি তার মতো?
রজারডপ্যাক

পার্থক্যটি বেশিরভাগ ক্ষেত্রে সিনট্যাকটিক। আমি তার থেকে পরিবর্তনশীল আরও fপরিষ্কার দেখতে পাই NR == FNR, তবে এটি স্বাদের বিষয়। হ্যাশটিতে নিয়োগ এত দ্রুত হওয়া উচিত যে দুটি সংস্করণের মধ্যে পরিমাপযোগ্য গতির পার্থক্য নেই। আমি মনে করি জটিলতায় আমি ভুল ছিলাম - যদি অনুসন্ধানটি স্থির থাকে তবে আপডেটটিও ধ্রুব হওয়া উচিত (গড়)। আমি জানি না কেন আমি আপডেট লোগারিদমিক হবে বলে মনে করি। আমি আমার উত্তর সম্পাদনা করব।
jcsahnwaldt মনিকা পুনরায় ইনস্টল করুন

আমি এই উত্তরগুলির একগুচ্ছ চেষ্টা করেছি, এবং এটি উত্তরটি দ্রুত গতিতে ছিল। আমার কয়েক হাজার লাইনের ফাইল ছিল। মোহন মত কাজ!
মিঃ টি

1
এটি আমার পছন্দসই সমাধান। এটা তোলে একাধিক ফাইল সঙ্গে কাজ করে এবং খালি ফাইল যেমন অগ্রাহ্য awk '{if (f==1) { r[$0] } else if (! ($0 in r)) { print $0 } } ' f=1 empty.file done.out failed.out f=2 all-files.out। অন্য awkসমাধানটি খালি বাদ দেওয়া ফাইলের সাথে ব্যর্থ হয় এবং কেবলমাত্র একটি নিতে পারে।
গ্রাহাম রাসেল

5

আপনার যদি রুবি থাকে (1.9+)

#!/usr/bin/env ruby 
b=File.read("file2").split
open("file1").each do |x|
  x.chomp!
  puts x if !b.include?(x)
end

যার ও (এন ^ 2) জটিলতা রয়েছে। আপনি যদি পারফরম্যান্স সম্পর্কে যত্ন নিতে চান তবে এখানে অন্য সংস্করণ

b=File.read("file2").split
a=File.read("file1").split
(a-b).each {|x| puts x}

বিয়োগফলকে প্রভাবিত করতে হ্যাশ ব্যবহার করে, তাই জটিলতা O (n) (a এর আকার) + O (n) (খের আকার)

এখানে একটি সামান্য বেঞ্চমার্ক, ব্যবহারকারীর সৌজন্যে 687687575,, তবে উপরের 100 ক লাইন সহ:

$ for i in $(seq 1 100000); do echo "$i"; done|sort --random-sort > file1
$ for i in $(seq 1 2 100000); do echo "$i"; done|sort --random-sort > file2
$ time ruby test.rb > ruby.test

real    0m0.639s
user    0m0.554s
sys     0m0.021s

$time sort file1 file2|uniq -u  > sort.test

real    0m2.311s
user    0m1.959s
sys     0m0.040s

$ diff <(sort -n ruby.test) <(sort -n sort.test)
$

diff উত্পন্ন 2 টি ফাইলের মধ্যে কোনও পার্থক্য নেই তা দেখানোর জন্য ব্যবহার করা হয়েছিল।


1
এতে O (n²) জটিলতা রয়েছে এবং একবারে কয়েকটি কে-লাইন ফাইলে ফাইলগুলি উপস্থিত হয়ে কয়েক ঘন্টা সময় নিতে শুরু করবে।
আরনাউড লে ব্ল্যাঙ্ক

আমি এই মুহুর্তে সত্যিই মাথা ঘামাই না, কারণ তিনি কোনও বড় ফাইল উল্লেখ করেননি।
কুড়ুমী

3
এতটা রক্ষণাত্মক হওয়ার দরকার নেই, এটি এমন নয় যে @ ইউজার 5776875 আপনার উত্তর বা কোনও কিছুকে হ্রাস করেছে। :-)
জন পার্কার

খুব সুন্দর দ্বিতীয় সংস্করণ, রুবি জিতল :)
আর্নাড লে ব্ল্যাঙ্ক

4

অন্যান্য বিভিন্ন উত্তরের মধ্যে কিছু সময় নির্ধারণের তুলনা:

$ for n in {1..10000}; do echo $RANDOM; done > f1
$ for n in {1..10000}; do echo $RANDOM; done > f2
$ time comm -23 <(sort f1) <(sort f2) > /dev/null

real    0m0.019s
user    0m0.023s
sys     0m0.012s
$ time ruby -e 'puts File.readlines("f1") - File.readlines("f2")' > /dev/null

real    0m0.026s
user    0m0.018s
sys     0m0.007s
$ time grep -xvf f2 f1 > /dev/null

real    0m43.197s
user    0m43.155s
sys     0m0.040s

sort f1 f2 | uniq -u এমনকি একটি প্রতিসম পার্থক্যও নয়, কারণ এটি উভয় ফাইলে একাধিকবার প্রদর্শিত লাইনগুলি সরিয়ে দেয় s

কম স্ট্যান্ডিন এবং এখানে স্ট্রিংয়ের সাহায্যে ব্যবহার করা যেতে পারে:

echo $'a\nb' | comm -23 <(sort) <(sort <<< $'c\nb') # a

2

এসকিউএলাইট শেলের জন্য উপযুক্ত কাজ বলে মনে হচ্ছে:

create table file1(line text);
create index if1 on file1(line ASC);
create table file2(line text);
create index if2 on file2(line ASC);
-- comment: if you have | in your files then specify  .separator ××any_improbable_string×× 
.import 'file1.txt' file1
.import 'file2.txt' file2
.output result.txt
select * from file2 where line not in (select line from file1);
.q

1

তুমি কি চেষ্টা করেছ এই sed সঙ্গে?

sed 's#^#sed -i '"'"'s%#g' f2 > f2.sh

sed -i 's#$#%%g'"'"' f1#g' f2.sh

sed -i '1i#!/bin/bash' f2.sh

sh f2.sh

0

কোনও 'প্রোগ্রামিং' উত্তর নয় তবে এখানে একটি দ্রুত এবং নোংরা সমাধান রয়েছে: কেবলমাত্র http://www.listdiff.com/compare-2-lists-differences-tool এ যান

স্পষ্টতই বিশাল ফাইলগুলির জন্য কাজ করবে না তবে এটি আমার জন্য কৌশলটি করেছে। কয়েকটি নোট:

  • আমি কোনওভাবেই ওয়েবসাইটের সাথে অনুমোদিত নই (যদি আপনি এখনও আমাকে বিশ্বাস না করেন তবে আপনি অনলাইনে অন্য কোনও সরঞ্জাম সন্ধান করতে পারেন; আমি অনুসন্ধান শব্দটি "সেট ডিফারেন্স তালিকা অনলাইন" ব্যবহার করেছি)
  • লিঙ্কযুক্ত ওয়েবসাইটটি প্রতিটি তালিকার তুলনায় নেটওয়ার্ক কল করছে বলে মনে হয়, তাই এটি কোনও সংবেদনশীল ডেটা খাওয়ান না
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.