অন্য ফাইল এ থেকে ফাইল বিতে প্রদর্শিত লাইনগুলি কীভাবে সরিয়ে ফেলবেন?


160

আমার কাছে একটি বড় ফাইল এ (ইমেল সমন্বিত) রয়েছে, প্রতিটি মেইলের জন্য একটি লাইন। আমার কাছে আরও একটি ফাইল বি রয়েছে যাতে মেলগুলির আরও একটি সেট থাকে।

এ-কে ফাইল বি থেকে উপস্থিত সমস্ত ঠিকানা মুছে ফেলার জন্য আমি কোন আদেশটি ব্যবহার করব?

সুতরাং, যদি ফাইল এ থাকে:

A
B
C

এবং ফাইল বি অন্তর্ভুক্ত:

B    
D
E

তারপরে এ ফাইলটি রেখে দেওয়া উচিত:

A
C

এখন আমি জানি এটি এমন একটি প্রশ্ন যা সম্ভবত প্রায়শই জিজ্ঞাসা করা হত তবে আমি কেবল অনলাইনে একটি কমান্ড পেয়েছি যা আমাকে একটি খারাপ ডিলিমিটারে ত্রুটি দিয়েছে gave

কোন সাহায্যের অনেক প্রশংসা হবে! কেউ অবশ্যই একটি চতুর ওয়ান-লাইনার নিয়ে আসবে, তবে আমি শেল বিশেষজ্ঞ নই।



1
বেশিরভাগ যদি এখানে উত্তরগুলি বাছাই করা ফাইলগুলির জন্য হয় এবং সর্বাধিক সুস্পষ্ট একটি অনুপস্থিত থাকে তবে কোনটি অবশ্যই আপনার দোষ নয়, তবে এটি অন্যটিকে আরও সাধারণভাবে কার্যকর করে তোলে।
ট্রিপলি

উত্তর:


203

ফাইলগুলি বাছাই করা থাকলে (সেগুলি আপনার উদাহরণে রয়েছে):

comm -23 file1 file2

-23লাইন উভয় ফাইল, বা শুধুমাত্র ফাইল 2. হন ফাইল বাছা হয় না শুষে, মাধ্যমে তাদের নল sortপ্রথম ...

দেখুন man পৃষ্ঠা এখানে


8
comm -23 file1 file2 > file3ফাইল 1 তে ফাইল 2 এ নয়, ফাইল 3 এ আউটপুট দেবে। এবং তারপরে mv file3 file1অবশেষে file1 এ অপ্রয়োজনীয় বিষয়বস্তু পরিষ্কার করা হবে।
বর্ণালী

2
বিকল্পভাবে, ব্যবহার করুন comm -23 file1 file2 | sponge file1। কোনও পরিষ্কারের প্রয়োজন নেই।
সোসোইই

ম্যান পেজ লিঙ্কটি আমার জন্য লোড হচ্ছে না - বিকল্প: linux.die.net/man/1/comm
ফেলিক্স রাবে

@ সোকোই @ স্পঞ্জ কি? আমার সিস্টেমে আমার তা নেই। (ম্যাকোস 10.13)
ফেলিক্স রাবে

@ ফেলিক্সরবে, বেশ, এটি ক্লান্তিকর। আপনার লিঙ্ক দিয়ে প্রতিস্থাপন করা হয়েছে। ধন্যবাদ
দ্য আরটিটিপাল পল

85

grep -Fvxf <lines-to-remove> <all-lines>

  • অ-বাছাই করা ফাইলগুলিতে কাজ করে
  • অর্ডার বজায় রাখে
  • পসিক্স

উদাহরণ:

cat <<EOF > A
b
1
a
0
01
b
1
EOF

cat <<EOF > B
0
1
EOF

grep -Fvxf B A

আউটপুট:

b
a
01
b

ব্যাখ্যা:

  • -F: ডিফল্ট BRE এর পরিবর্তে আক্ষরিক স্ট্রিং ব্যবহার করুন
  • -x: সম্পূর্ণ লাইন মেলে এমন ম্যাচগুলি কেবল বিবেচনা করুন
  • -v: অ-মিল মুদ্রণ
  • -f file: প্রদত্ত ফাইল থেকে নিদর্শন নিন

এই পদ্ধতিটি অন্যান্য পদ্ধতির তুলনায় প্রাক-বাছাই করা ফাইলগুলিতে ধীর। যদি গতিটিও গুরুত্বপূর্ণ হয় তবে দেখুন: অন্য কোনও ফাইল নয় এমন একটি ফাইলের লাইনগুলি খুঁজে পাওয়ার দ্রুত উপায়?

ইন-লাইন অপারেশনের জন্য এখানে একটি দ্রুত বাশ অটোমেশন রয়েছে:

remove-lines() (
  remove_lines="$1"
  all_lines="$2"
  tmp_file="$(mktemp)"
  grep -Fvxf "$remove_lines" "$all_lines" > "$tmp_file"
  mv "$tmp_file" "$all_lines"
)

গিটহাব উজানের দিকে

ব্যবহার:

remove-lines lines-to-remove remove-from-this-file

আরও দেখুন: /unix/28158/is-there-a-tool-to-get-the-lines-in-one-file-that-are-not-in-another


55

উদ্ধার!

এই সমাধানটির জন্য বাছাই করা ইনপুট দরকার হয় না। আপনাকে প্রথমে ফাইলবি সরবরাহ করতে হবে।

awk 'NR==FNR{a[$0];next} !($0 in a)' fileB fileA

আয়

A
C

এটা কিভাবে কাজ করে?

NR==FNR{a[$0];next} আইডিয়োম একটি মিশ্র অ্যারেতে প্রথম ফাইলটি পরে "অন্তর্ভুক্ত" পরীক্ষার কী হিসাবে সংরক্ষণ করার জন্য।

NR==FNR আমরা প্রথম ফাইলটি স্ক্যান করছি কিনা তা যাচাই করা হচ্ছে, যেখানে গ্লোবাল লাইন কাউন্টার (এনআর) বর্তমান ফাইল লাইন কাউন্টার (এফএনআর) এর সমান।

a[$0] এসোসিয়েটিভ অ্যারেতে বর্তমান লাইনটি কী হিসাবে যুক্ত করেছে, নোট করুন যে এটি একটি সেটের মতো আচরণ করে, যেখানে কোনও সদৃশ মান (কী) থাকবে না

!($0 in a)আমরা এখন পরের ফাইল (গুলি) এ inআছি , এটি একটি পরীক্ষা রয়েছে, এখানে এটি পরীক্ষা করা হচ্ছে যে বর্তমান লাইনটি প্রথম ফাইল থেকে প্রথম ধাপে আমরা জনবহুল সেটে !রয়েছি কিনা তা শর্তটি উপেক্ষা করে। এখানে যা অনুপস্থিত তা হ'ল ক্রিয়া, যা পূর্বনির্ধারিত হয় {print}এবং সাধারণত স্পষ্টভাবে লেখা হয় না।

নোট করুন যে এটি এখন কালো তালিকাভুক্ত শব্দগুলি সরাতে ব্যবহার করা যেতে পারে।

$ awk '...' badwords allwords > goodwords

সামান্য পরিবর্তন সহ এটি একাধিক তালিকা পরিষ্কার করতে পারে এবং পরিষ্কার সংস্করণ তৈরি করতে পারে।

$ awk 'NR==FNR{a[$0];next} !($0 in a){print > FILENAME".clean"}' bad file1 file2 file3 ...

এই উপর সম্পূর্ণ চিহ্ন। এটি উইন্ডোতে GnuWin32-এ কমান্ড লাইনে ব্যবহার করতে একক নিবলগুলি ডাবল উদ্ধৃতি সহ প্রতিস্থাপন করুন। একটি ট্রিট কাজ করে। অনেক ধন্যবাদ.
twobob

এটি কাজ করে তবে আমি কীভাবে আউটপুট এএ (নতুন লাইনের সাথে) বি এর আকারে ফাইলএতে পুনর্নির্দেশ করতে সক্ষম হব
আনন্দ বিল্ডার

আমার ধারণা আপনার অর্থ A\nC, প্রথমে একটি ... > tmp && mv tmp fileA
টেম্পল

আমার কাছ থেকে এটিতেও পূর্ণ চিহ্ন। এই বার্তায় 104,000 এন্ট্রি সহ একটি ফাইল প্রক্রিয়া করতে 1 সেকেন্ডের সমস্ত লাগে: +1:
মিচেলকে

স্ক্রিপ্টগুলিতে এটি ব্যবহার করার সময়, নিশ্চিত হয়ে নিন যে fileBএটি খালি নয় (0 বাইট দীর্ঘ), কারণ এটি যদি হয় তবে আপনি প্রত্যাশিত সামগ্রীর পরিবর্তে একটি খালি ফলাফল পাবেন fileA। (কারণ: FNR==NRfileA
ততক্ষণে

18

একই জিনিসটি করার আরেকটি উপায় (এছাড়াও সাজানো ইনপুট প্রয়োজন):

join -v 1 fileA fileB

বাশ-এ, ফাইলগুলি আগে-বাছাই না করা থাকলে:

join -v 1 <(sort fileA) <(sort fileB)

7

আপনার ফাইলগুলি বাছাই করা না হলে আপনি এটি করতে পারেন

diff file-a file-b --new-line-format="" --old-line-format="%L" --unchanged-line-format="" > file-a

--new-line-formatযে ফাইলগুলি বি তে আছে তবে একটিতে নয় --old-..এমন লাইনের জন্য যা ফাইল এ-তে রয়েছে তবে --unchanged-..বিতে নয় এমন উভয় লাইনের জন্য for %Lএটি তৈরি করে যাতে লাইনটি ঠিক ছাপা হয় printed

man diff

আরো বিস্তারিত জানার জন্য


1
আপনি বলছেন যে ফাইলগুলি বাছাই করা না হলে এটি কাজ করবে। বাছাই করলে কোন সমস্যা হয়? সেগুলি আংশিকভাবে বাছাই করা হলে কী হবে?
কার্লোস ম্যাসাসেট

1
এটি উপরের সমাধানটির প্রতিক্রিয়া হিসাবে commকমান্ডের ব্যবহারের পরামর্শ দেয় । commফাইলগুলি বাছাই করা দরকার, সুতরাং সেগুলি সাজানো থাকলে আপনি সেই সমাধানটিও ব্যবহার করতে পারেন। ফাইলটি বাছাই করা হয়েছে কিনা তা বিবেচনা না করেই আপনি এই সমাধানটি ব্যবহার করতে পারেন
aec

7

@ কারকফার দুর্দান্ত উত্তরের এই পরিশোধনটি খুব বড় ফাইলগুলির জন্য লক্ষণীয়ভাবে দ্রুত হতে পারে। এই উত্তরের মতো, দুটি ফাইলই বাছাই করা দরকার না, তবে গতি অজস্রের সহযোগী অ্যারেগুলির দ্বারা নিশ্চিত করা হয়। কেবল লুকিং ফাইলটি মেমরিতে রাখা হয়।

এই সূত্রটি সেই সম্ভাবনার পক্ষেও মঞ্জুরি দেয় যে ইনপুট ফাইলে কেবলমাত্র একটি নির্দিষ্ট ক্ষেত্র ($ N) তুলনা করতে ব্যবহৃত হবে।

# Print lines in the input unless the value in column $N
# appears in a lookup file, $LOOKUP;
# if $N is 0, then the entire line is used for comparison.

awk -v N=$N -v lookup="$LOOKUP" '
  BEGIN { while ( getline < lookup ) { dictionary[$0]=$0 } }
  !($N in dictionary) {print}'

(এই পদ্ধতির আরেকটি সুবিধা হ'ল তুলনার মানদণ্ডটি সংশোধন করা সহজ, উদাহরণস্বরূপ শীর্ষস্থানীয় এবং অনুসরণকারী সাদা স্থানকে ছাঁটাই করা))


অন্য একটি লাইনারের চেয়ে কর্নার-কেস ক্রস প্ল্যাটফর্মের দৃশ্যে এটি ব্যবহার করা আরও শক্ত। তবে পারফরম্যান্স প্রচেষ্টাতে টুপি
18'16 এ 1-2

2

আপনি পাইথন ব্যবহার করতে পারেন:

python -c '
lines_to_remove = set()
with open("file B", "r") as f:
    for line in f.readlines():
        lines_to_remove.add(line.strip())

with open("file A", "r") as f:
    for line in [line.strip() for line in f.readlines()]:
        if line not in lines_to_remove:
            print(line)
'

2

তুমি ব্যবহার করতে পার - diff fileA fileB | grep "^>" | cut -c3- > fileA

এটি সেই ফাইলগুলির জন্য কাজ করবে যেগুলি সাজানো হয় না।


-1

দুটি ফাইলের মধ্যে সাধারণ লাইনগুলি সরাতে আপনি গ্রেপ, কম বা কমান্ড কমান্ড ব্যবহার করতে পারেন।

গ্রেপ শুধুমাত্র ছোট ফাইলগুলির জন্য কাজ করে। -F এর সাথে -v ব্যবহার করুন।

grep -vf file2 file1 

এটি ফাইল 1 থেকে লাইনগুলি প্রদর্শন করে যা ফাইল 2 এর সাথে কোনও লাইনের সাথে মেলে না।

কম একটি ইউটিলিটি কমান্ড যা লিক্সিকালি সাজানো ফাইলগুলিতে কাজ করে। এটি ইনপুট হিসাবে দুটি ফাইল নেয় এবং আউটপুট হিসাবে তিনটি পাঠ্য কলাম তৈরি করে: কেবল প্রথম ফাইলটিতে লাইন; কেবলমাত্র দ্বিতীয় ফাইলে লাইনগুলি; এবং উভয় ফাইলের লাইন। আপনি সেই অনুযায়ী -1, -2 বা -3 বিকল্প ব্যবহার করে যে কোনও কলামের মুদ্রণ দমন করতে পারেন।

comm -1 -3 file2 file1

এটি ফাইল 1 থেকে লাইনগুলি প্রদর্শন করে যা ফাইল 2 এর সাথে কোনও লাইনের সাথে মেলে না।

পরিশেষে, সেখানে যোগদান, একটি ইউটিলিটি কমান্ড নির্দিষ্ট ফাইলগুলিতে সমতা যোগদানের কাজ করে। এর -v বিকল্পটি দুটি ফাইলের মধ্যে সাধারণ লাইনগুলি সরাতে দেয়।

join -v1 -v2 file1 file2

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