বাশ থেকে "গ্রুপ বাই" সিমুলেট করার সর্বোত্তম উপায়?


231

মনে করুন আপনার কাছে এমন একটি ফাইল রয়েছে যার মধ্যে আইপি ঠিকানা রয়েছে, প্রতিটি লাইনে একটি করে ঠিকানা:

10.0.10.1
10.0.10.1
10.0.10.3
10.0.10.2
10.0.10.1

আপনার কাছে একটি শেল স্ক্রিপ্ট দরকার যা প্রতিটি আইপি ঠিকানার জন্য গণনা করা হয় যে এটি ফাইলটিতে কতবার প্রদর্শিত হয়। পূর্ববর্তী ইনপুট জন্য আপনার নিম্নলিখিত আউটপুট প্রয়োজন:

10.0.10.1 3
10.0.10.2 1
10.0.10.3 1

এটি করার একটি উপায়:

cat ip_addresses |uniq |while read ip
do
    echo -n $ip" "
    grep -c $ip ip_addresses
done

তবে এটি দক্ষ হওয়ার থেকে দূরে।

বাশ ব্যবহার করে আপনি কীভাবে এই সমস্যার সমাধান করবেন?

(যোগ করার জন্য একটি জিনিস: আমি জানি যে এটি পার্ল বা অজানা থেকে সমাধান করা যেতে পারে, আমি ব্যাশে আরও ভাল সমাধানে আগ্রহী, সে ভাষাগুলিতে নয়))

অতিরিক্ত তথ্য:

ধরা যাক উত্স ফাইলটি 5 গিগাবাইট এবং অ্যালগরিদম চালিত মেশিনটিতে 4 জিবি রয়েছে। সুতরাং বাছাই একটি কার্যকর সমাধান নয়, না হয় একাধিকবার ফাইল পড়া হয়।

আমি হ্যাশটেবল-জাতীয় সমাধান পছন্দ করেছি - যে কেউ এই সমাধানটির উন্নতি দিতে পারে?

অতিরিক্ত তথ্য # 2:

কিছু লোক জিজ্ঞাসা করেছিল যে যখন আমি যেমন পার্লের উপায়ে সহজতর হয় তখন কেন আমি ব্যাশ করে এটি করা বিরক্ত করব। কারণটি হ'ল যে মেশিনে আমাকে এই পার্লটি করতে হয়েছিল তা আমার জন্য উপলব্ধ ছিল না। এটি আমার ব্যবহৃত বেশিরভাগ সরঞ্জাম ছাড়াই একটি কাস্টম বিল্ট লিনাক্স মেশিন ছিল। এবং আমি মনে করি এটি একটি আকর্ষণীয় সমস্যা ছিল।

সুতরাং দয়া করে, প্রশ্নটিকে দোষারোপ করবেন না, যদি এটি পছন্দ না করেন তবে এটিকে এড়িয়ে যান। :-)


আমি মনে করি বাশ কাজের জন্য ভুল সরঞ্জাম tool পার্ল সম্ভবত একটি ভাল সমাধান হতে পারে।
ফ্রাঙ্কোয়েস ওলমারান্স

উত্তর:


412
sort ip_addresses | uniq -c

এটি প্রথমে কাউন্টটি মুদ্রণ করবে, তবে এগুলি ছাড়া আপনি যা চান ঠিক তা হওয়া উচিত।


71
যা আপনি তারপরে ক্রমানুসারে সাজানো বাছাই করতে "সাজানোর -nr" এ পাইপ করতে পারেন, সর্বোচ্চ থেকে সর্বনিম্ন গণনাতে। যেমনsort ip_addresses | uniq -c | sort -nr
ব্র্যাড পার্কগুলি

15
এবং sort ip_addresses | uniq -c | sort -nr | awk '{ print $2, $1 }'প্রথম কলামে আইপি ঠিকানা পেতে এবং দ্বিতীয়টিতে গণনা করুন।
রঘু দোডা

সাজানোর অংশের জন্য আরও একটি টুইট:sort -nr -k1,1
আন্দ্রেজ মার্টিনা

50

দ্রুত এবং নোংরা পদ্ধতিটি নিম্নরূপ:

cat ip_addresses | sort -n | uniq -c

আপনার যদি ব্যাশের মানগুলি ব্যবহার করতে হয় তবে আপনি সম্পূর্ণ কমান্ডটিকে ব্যাশ ভেরিয়েবলের কাছে নির্ধারণ করতে পারেন এবং তারপরে ফলাফলগুলি লুপ করতে পারেন।

পুনশ্চ

যদি সাজানোর আদেশটি বাদ দেওয়া হয় তবে আপনি সঠিক ফলাফল পাবেন না কারণ ইউনিক কেবল একের পর এক অভিন্ন লাইন দেখায়।


এটি একেবারে দক্ষতার
ভিত্তিতে

চতুর্ভুজ অর্থ ও (n ^ 2) ?? এটি অবশ্যই বাছাই করা অ্যালগরিদমের উপর নির্ভর করবে, এটি যেমন বোগো-বাছাই করা সম্ভব নয়।
paxdiablo

ঠিক আছে, সর্বোত্তম ক্ষেত্রে এটি ও (এন লগ (এন)) হবে, যা দুটি পাসের চেয়ে খারাপ (যা আপনি তুচ্ছ হ্যাশ ভিত্তিক বাস্তবায়নের মাধ্যমে পান)। আমার চতুর্ভুজটির পরিবর্তে 'সুপারলাইনার' বলা উচিত ছিল।
ভিঙ্কো ভার্সালোভিক

এবং এটি এখনও একই
সীমানায় রয়েছে

11
ইউউক, বিড়ালের অকেজো ব্যবহার

22

বিদ্যমান ক্ষেত্রগুলির একটি গোষ্ঠীর উপর ভিত্তি করে একাধিক ক্ষেত্র সংক্ষিপ্তকরণের জন্য নীচের উদাহরণটি ব্যবহার করুন: (আপনার প্রয়োজনীয়তা অনুসারে $ 1, $ 2, $ 3, $ 4 প্রতিস্থাপন করুন)

cat file

US|A|1000|2000
US|B|1000|2000
US|C|1000|2000
UK|1|1000|2000
UK|1|1000|2000
UK|1|1000|2000

awk 'BEGIN { FS=OFS=SUBSEP="|"}{arr[$1,$2]+=$3+$4 }END {for (i in arr) print i,arr[i]}' file

US|A|3000
US|B|3000
US|C|3000
UK|1|9000

2
+1 কারণ এটি দেখায় যখন কেবল গণনা প্রয়োজন হয় না তখন কী করা উচিত
user829755

1
+1 কারণ sortএবং uniqএটি গণনা করার পক্ষে সবচেয়ে সহজ, তবে আপনাকে যখন ক্ষেত্রের মানগুলি / সংখ্যার প্রয়োজন হয় তার প্রয়োজন হয় না। awk এর অ্যারে সিনট্যাক্সটি খুব শক্তিশালী এবং এখানে গ্রুপিংয়ের মূল চাবিকাঠি। ধন্যবাদ!
অদ্ভুত

1
আরও একটি জিনিস, সতর্ক awk এর যে print2 ^ 31 মাত্রাধিক int- এ মানের জন্য ফাংশন 32 বিট 64 বিট ইন্টিজার downscale বলে মনে হয়, তাই আপনি ব্যবহার করতে পারেন printfসঙ্গে %.0fপরিবর্তে বিন্যাস printসেখানে
odony

1
সংখ্যার সংখ্যার পরিবর্তে স্ট্রিং কনটেন্টেশন দিয়ে "গোষ্ঠী দ্বারা" সন্ধান করা লোকেরা arr[$1,$2]+=$3+$4যেমন arr[$1,$2]=(arr[$1,$2] $3 "," $4). I needed this to provide a grouped-by-package list of files (two columns only) and used: সফলভাবে আরআর [$ 1] = (আরআর [$ 1] $ 2) `এর সাথে প্রতিস্থাপন করবে ।
স্টাফেন গৌরিচন

20

ক্যানোনিকাল সমাধানটি হ'ল অন্য উত্তরদাতার দ্বারা বর্ণিত একটি:

sort | uniq -c

পার্ল বা অজানাতে কী লেখা যায় তার চেয়ে এটি সংক্ষিপ্ত এবং আরও সংক্ষিপ্ত।

আপনি লিখেছেন যে আপনি বাছাই করতে চান না, কারণ ডেটার আকার মেশিনের প্রধান মেমরির আকারের চেয়ে বড়। ইউনিক্স বাছাই কমান্ডের প্রয়োগের গুণমানকে কম মূল্য দেবেন না। বাছাইটি 128 কে (131,072 বাইট) মেমরির (পিডিপি -11) সহ মেশিনগুলিতে খুব বড় পরিমাণে ডেটা (মূল এটিটি এবং টি এর বিলিং ডেটা মনে করুন) পরিচালনা করতে ব্যবহৃত হয়েছিল। যখন সাজানোর কোনও প্রিসেট সীমা ছাড়িয়ে বেশি ডেটার মুখোমুখি হয় (প্রায়শই মেশিনের প্রধান মেমরির আকারের সাথে সংযুক্ত করা হয়) এটি মূল স্মৃতিতে পড়া ডেটাটি সাজায় এবং একটি অস্থায়ী ফাইলে লেখায়। এটি পরবর্তী তথ্যগুলির সাথে ক্রিয়াটি পুনরাবৃত্তি করে। শেষ পর্যন্ত, এটি those মধ্যবর্তী ফাইলগুলিতে একত্রিতকরণ বাছাই করে। এটি মেশিনের প্রধান মেমরির থেকে বহুগুণ বড় ডেটাতে सॉर्टকে কাজ করতে দেয়।


ঠিক আছে, এটি এখনও একটি হ্যাশ গণনার চেয়ে খারাপ, না? আপনি কি জানেন যে ডেটা মেমরির সাথে খাপ খায় তবে কি বাছাইয়ের অ্যালগরিদম ব্যবহার করে? এটি সংখ্যা সংক্রান্ত ডেটা কেস (-n বিকল্প) এর মধ্যে পৃথক হতে পারে?
ভিঙ্কো ভার্সালভিক

এটি কীভাবে বাছাই করে (1) প্রয়োগ করা হয় তার উপর নির্ভর করে। GNU বাছাই (লিনাক্স বিতরণে ব্যবহৃত) এবং BSD সাজান উভয়ই যথাযথ অ্যালগরিদম ব্যবহার করতে বড় দৈর্ঘ্যে যায় to
ডায়োমিডিস স্পিনেলিস

9
cat ip_addresses | sort | uniq -c | sort -nr | awk '{print $2 " " $1}'

এই কমান্ডটি আপনাকে পছন্দসই আউটপুট দেবে


4

দেখে মনে হচ্ছে আপনি রৈখিক আচরণ পেতে বাশগুলিতে হ্যাশগুলি অনুকরণ করতে প্রচুর পরিমাণ কোড ব্যবহার করতে হবে বা চতুর্ভুজীয় সুপারলাইনারের সংস্করণে লেগে থাকবে।

এই সংস্করণগুলির মধ্যে, সউয়ার সমাধানটি সেরা (এবং সবচেয়ে সহজ):

sort -n ip_addresses.txt | uniq -c

আমি http://unix.derkeiler.com/Newsgroups/comp.unix.shell/2005-11/0118.html খুঁজে পেয়েছি । তবে এটি জাহান্নামের মতো কুৎসিত ...


আমি রাজী. এটি এখন পর্যন্ত সেরা সমাধান এবং অনুরূপ সমাধান পার্ল এবং অজানাতে সম্ভব। কেউ কি ব্যাশে ক্লিনার প্রয়োগের ব্যবস্থা করতে পারে?
জিজ্জেঙ্কস

আমি যে জানি না। আপনি হ্যাশগুলিকে সমর্থনকারী ভাষাগুলিতে আরও ভাল বাস্তবায়ন পেতে পারেন, যেখানে আপনি আমার ip ip (@ips) {$ হ্যাশ {ip} = $ হ্যাশ {ip} + 1; } এবং তারপরে কেবল কীগুলি এবং মানগুলি মুদ্রণ করুন।
ভিঙ্কো ভার্সালোভিক

4

সমাধান (মাইএসকিএলের মতো গ্রুপ)

grep -ioh "facebook\|xing\|linkedin\|googleplus" access-log.txt | sort | uniq -c | sort -n

ফলাফল

3249  googleplus
4211 linkedin
5212 xing
7928 facebook

3

আপনি সম্ভবত ফাইল সিস্টেমটি হ্যাশ টেবিল হিসাবে ব্যবহার করতে পারেন। সিউডো কোড নিম্নরূপ:

for every entry in the ip address file; do
  let addr denote the ip address;

  if file "addr" does not exist; then
    create file "addr";
    write a number "0" in the file;
  else 
    read the number from "addr";
    increase the number by 1 and write it back;
  fi
done

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


3

আমি মনে করি অজানা সাহসী অ্যারেও এক্ষেত্রে কার্যকর

$ awk '{count[$1]++}END{for(j in count) print j,count[j]}' ips.txt

এখানে পোস্ট করে একটি গ্রুপ


ইয়াপ্প, দুর্দান্ত অ্যাডক সমাধান, কিন্তু অ্যাডক আমি যে মেশিনটি চালিয়ে যাচ্ছিলাম তা কেবলমাত্র অবিচল ছিল না।
জিজ্জনস

1

অন্যান্য সমাধানগুলির বেশিরভাগই সদৃশ গণনা করে। আপনার যদি সত্যই কী মান জোড়গুলি গ্রুপ করতে হয় তবে এটি চেষ্টা করুন:

এখানে আমার উদাহরণ ডেটা:

find . | xargs md5sum
fe4ab8e15432161f452e345ff30c68b0 a.txt
30c68b02161e15435ff52e34f4fe4ab8 b.txt
30c68b02161e15435ff52e34f4fe4ab8 c.txt
fe4ab8e15432161f452e345ff30c68b0 d.txt
fe4ab8e15432161f452e345ff30c68b0 e.txt

এটি এমডি 5 চেকসাম দ্বারা গ্রুপযুক্ত মূল মান জোড়গুলি মুদ্রণ করবে।

cat table.txt | awk '{print $1}' | sort | uniq  | xargs -i grep {} table.txt
30c68b02161e15435ff52e34f4fe4ab8 b.txt
30c68b02161e15435ff52e34f4fe4ab8 c.txt
fe4ab8e15432161f452e345ff30c68b0 a.txt
fe4ab8e15432161f452e345ff30c68b0 d.txt
fe4ab8e15432161f452e345ff30c68b0 e.txt

1

বিশুদ্ধ (কোন কাঁটাচামচ!)

একটি উপায় আছে, ব্যবহার করে ফাংশন । কাঁটাচামচ না থাকায় এই পথটি খুব দ্রুত! ...

... যদিও গুচ্ছ IP ঠিকানা থাকার ছোট !

countIp () { 
    local -a _ips=(); local _a
    while IFS=. read -a _a ;do
        ((_ips[_a<<24|${_a[1]}<<16|${_a[2]}<<8|${_a[3]}]++))
    done
    for _a in ${!_ips[@]} ;do
        printf "%.16s %4d\n" \
          $(($_a>>24)).$(($_a>>16&255)).$(($_a>>8&255)).$(($_a&255)) ${_ips[_a]}
    done
}

দ্রষ্টব্য: আইপি ঠিকানাগুলি 32 বিট স্বাক্ষরিত স্বাক্ষর পূর্ণসংখ্যার মানে রূপান্তরিত হয়, অ্যারের সূচক হিসাবে ব্যবহৃত হয় । এটি সাধারণ ব্যাশ অ্যারেগুলি ব্যবহার করে , সহযোগী অ্যারে নয় (যা আরও ব্যয়বহুল)!

time countIp < ip_addresses 
10.0.10.1    3
10.0.10.2    1
10.0.10.3    1
real    0m0.001s
user    0m0.004s
sys     0m0.000s

time sort ip_addresses | uniq -c
      3 10.0.10.1
      1 10.0.10.2
      1 10.0.10.3
real    0m0.010s
user    0m0.000s
sys     0m0.000s

আমার হোস্টে, এটি করা প্রায় 1'000 ঠিকানা পর্যন্ত কাঁটাচামচ ব্যবহারের চেয়ে খুব দ্রুত, তবে আমি যখন 10'000 ঠিকানাগুলিকে গণনা করার চেষ্টা করব তখন প্রায় 1 সম্পূর্ণ দ্বিতীয়টি নিন।


0

আমি এটি এইভাবে করতাম:

perl -e 'while (<>) {chop; $h{$_}++;} for $k (keys %h) {print "$k $h{$k}\n";}' ip_addresses

তবে ইউনিক আপনার জন্য কাজ করতে পারে।


আমি মূল পোস্ট পার্ল হিসাবে বলেছি একটি বিকল্প নয়। আমি জানি
পার্লে

0

আমি বুঝতে পেরেছি আপনি বাশের জন্য কিছু সন্ধান করছেন, তবে যদি পাইথনে অন্য কেউ কিছু খুঁজছেন তবে আপনি এটি বিবেচনা করতে পারেন:

mySet = set()
for line in open("ip_address_file.txt"):
     line = line.rstrip()
     mySet.add(line)

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

সম্পাদনা: আমি একজন দুষ্টু পাঠক, তাই আমি ভুল উত্তর দিয়েছি। এখানে একটি ডিক সহ একটি স্নিপেট রয়েছে যা ঘটনাগুলি গণনা করবে।

mydict = {}
for line in open("ip_address_file.txt"):
    line = line.rstrip()
    if line in mydict:
        mydict[line] += 1
    else:
        mydict[line] = 1

অভিধান মাইডিক্ট এখন কী হিসাবে অনন্য আইপি'র একটি তালিকা এবং কতগুলি সময় তাদের মান হিসাবে ঘটেছে তা ধারণ করে।


এটি কিছুই গণনা করে না। আপনার একটি ডিক দরকার যা স্কোর বজায় রাখে।

ডোহ। প্রশ্নের খারাপ পড়া, দুঃখিত। মূলত প্রতিটি আইপি ঠিকানার পরিমাণের পরিমাণ সংরক্ষণ করার জন্য ডিক ব্যবহার করার বিষয়ে আমার কাছে কিছুটা ছিল তবে এটি সরিয়ে ফেললাম, কারণ, ভাল, আমি প্রশ্নটি খুব ভাল করে পড়িনি। * সঠিকভাবে জাগ্রত হওয়ার চেষ্টা করে
wzzrd

2
এর মধ্যে একটি রয়েছে itertools.groupby()যা sorted()ওপি জিজ্ঞাসা করে ঠিক তাই করে।
jfs


-8

ক্রমটি বাদ দেওয়া যেতে পারে যদি অর্ডারটি উল্লেখযোগ্য না হয়

uniq -c <source_file>

অথবা

echo "$list" | uniq -c

যদি উত্স তালিকাটি একটি পরিবর্তনশীল হয়


1
আরও স্পষ্ট করতে ইউনিক ম্যান পৃষ্ঠা থেকে: দ্রষ্টব্য: 'ইউনিীক' পুনরাবৃত্ত লাইনগুলি সংলগ্ন না করে সনাক্ত করে না। আপনি প্রথমে ইনপুটটি বাছাই করতে চাইতে পারেন বা 'ইউনিট' ছাড়াই 'সাজ্ট-ইউ' ব্যবহার করতে পারেন।
রূপান্তরকারী
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.