প্রথম লাইন ব্যতীত ফাইল থেকে অতিরিক্ত শিরোনামের লাইনগুলি সরান


18

আমার কাছে এমন একটি ফাইল রয়েছে যা এই খেলনার উদাহরণের মতো দেখায়। আমার আসল ফাইলে 4 মিলিয়ন লাইন রয়েছে যার মধ্যে 10 টি মুছতে হবে।

ID  Data1  Data2
1    100    100
2    100    200
3    200    100
ID  Data1  Data2
4    100    100
ID  Data1  Data2
5    200    200

আমি প্রথম লাইনটি বাদ দিয়ে শিরোনামের মতো দেখতে পাওয়া লাইনগুলি মুছতে চাই।

চূড়ান্ত ফাইল:

ID  Data1  Data2
1    100    100
2    100    200
3    200    100
4    100    100
5    200    200

কিভাবে আমি এটি করতে পারব?

উত্তর:


26
header=$(head -n 1 input)
(printf "%s\n" "$header";
 grep -vFxe "$header" input
) > output
  1. ইনপুট ফাইল থেকে একটি চলক হিসাবে শিরোনাম লাইন ধরুন
  2. শিরোনামটি মুদ্রণ করুন
  3. grepশিরোনামের সাথে মেলে এমন লাইনগুলি বাদ দিতে ফাইলটি প্রসেস করুন
  4. উপরের দুটি পদক্ষেপ থেকে আউটপুট আউটপুট ফাইলে ক্যাপচার করুন

2
বা সম্ভবত{ IFS= read -r head; printf '%s\n' "$head"; grep -vF "$head" ; } <file
ইরুভর

উভয় ভাল সংযোজন। Don_crissti কে পরোক্ষভাবে নির্দেশ করে যে পজিক্স সম্প্রতি -1 সিনট্যাক্সটি মাথা থেকে 1n- এর পক্ষে সরিয়ে নিয়েছে
জেফ শ্যাচলার

3
@JeffSchaller, সম্প্রতি 12 বছর আগে হয়ে থাকে। এবং head -1এর আগে কয়েক দশক ধরে অপ্রচলিত।
স্টাফেন চেজেলাস

36

তুমি ব্যবহার করতে পার

sed '2,${/ID/d;}'

এটি লাইন 2 থেকে শুরু করে আইডি সহ লাইনগুলি মুছে ফেলবে।


3
চমৎকার; বা প্যাটার্ন মিলের সাথে আরও সুনির্দিষ্ট হতে হবে sed '2,${/^ID Data1 Data2$/d;}' file(অবশ্যই কলামগুলির মধ্যে ফাঁকের সঠিক সংখ্যা ব্যবহার করে)
জেফ শ্যাচলার

এইচএম আমি ভেবেছিলাম আপনি কেবল 1 টি কমান্ডের জন্য অর্ধপরিচয়টি বাদ দিতে পারেন, তবে ঠিক আছে।
বেকমনি

ডাব্লু / সেনে sedনেই, না
মাইকজার্ভ

ইন-প্লেস সম্পাদনা জয়ের জন্য আইএআ্যান্ড -i।
ব্যবহারকারী 2066657


10

যারা কোঁকড়া বন্ধনী পছন্দ করেন না তাদের জন্য

sed -e '1n' -e '/^ID/d'
  • nমানে passলাইন নং1
  • d শুরু হওয়া সমস্ত মিলিত লাইন মুছে ফেলুন ^ID

5
এটি sed '1n;/^ID/d'ফাইলের নাম থেকেও সংক্ষিপ্ত করা যেতে পারে । কেবলমাত্র একটি পরামর্শ
ভ্যালেন্টাইন বাজরামি

মনে রাখবেন যে IDfooএটি শিরোনামের মতো নয় এমন লাইনগুলিও মুদ্রণ করবে (এই ক্ষেত্রে কোনও পার্থক্য আনার সম্ভাবনা নেই, তবে আপনি কখনই জানেন না)।
টেরডন

6

এখানে একটি মজা। sedপ্রথম লাইনের সমস্ত অনুলিপি বের করে ফেলার জন্য আপনি সরাসরি ব্যবহার করতে পারেন এবং সমস্ত কিছু জায়গায় রেখে (প্রথম লাইনটি নিজেই সহ)।

sed '1{h;n;};G;/^\(.*\)\n\1$/d;s/\n.*$//' input

1{h;n;}হোল্ড স্পেসে প্রথম লাইন রাখে, এটি মুদ্রণ করে এবং পরের লাইনে পড়ে — sedপ্রথম লাইনের জন্য বাকি কমান্ডগুলি এড়িয়ে চলে। (এটি দ্বিতীয় লাইনের জন্য প্রথম 1পরীক্ষাটিও এড়িয়ে যায় , তবে সেই পরীক্ষার ফলে দ্বিতীয় লাইনে প্রয়োগ হত না matter

G প্যাটার্ন স্পেসে হোল্ড স্পেসের সামগ্রীগুলি অনুসরণ করে একটি নতুন লাইন যুক্ত করে।

/^\(.*\)\n\1$/dপ্যাটার্ন স্পেসের সামগ্রীগুলি মুছে ফেলে (এভাবে পরবর্তী লাইনে এড়িয়ে যাওয়া) যদি নিউলাইনের পরে অংশটি (যেমন হোল্ড স্পেস থেকে সংযোজন করা হয়েছিল) নতুন লাইনের আগে অংশটির সাথে মেলে। এখানেই শিরোনামের সদৃশ হওয়া লাইনগুলি মুছে ফেলা হবে।

s/\n.*$//Gকমান্ড দ্বারা যোগ করা পাঠ্যের অংশটি মুছে দেয় , যাতে যা মুদ্রিত হয় তা কেবল ফাইল থেকে পাঠ্যের লাইন।

তবে, যেহেতু রেজেক্স ব্যয়বহুল, তাই সামান্য দ্রুত পদ্ধতির ক্ষেত্রে একই শর্তটি (অবহেলিত) ব্যবহার Pকরা হবে এবং যদি নতুন লাইনের পরে অংশটি (যেমন হোল্ড স্পেস থেকে সংযোজন করা হয়েছিল) অংশটির সাথে সঠিকভাবে মেলে না তবে নতুন লাইনটি ছড়িয়ে দেওয়া উচিত নতুন লাইনের আগে এবং তারপরে নিঃশর্তভাবে প্যাটার্ন স্পেসটি মুছুন:

sed '1{h;n;};G;/^\(.*\)\n\1$/!P;d' input

আপনার ইনপুট দেওয়া হলে আউটপুট হয়:

ID  Data1  Data2
1    100    100
2    100    200
3    200    100
4    100    100
5    200    200


@ ডন_ক্রিসটি, আকর্ষণীয় সংযোজন; ধন্যবাদ! আমি সম্ভবত দীর্ঘতর কিন্তু সমতুল্য হয়ে উঠতে চাই sed '1{h;n;};G;/^\(.*\)\n\1$/d;P;d' input; আমার পক্ষে এটি পড়া সহজতর easier :)
ওয়াইল্ডকার্ড

এছাড়াও সম্পর্কিত: unix.stackexchange.com/a/417736/135943
ওয়াইল্ডকার্ড

5

এখানে আরও কয়েকটি পছন্দ রয়েছে যা আপনাকে প্রথম লাইনের আগাম জানতে হবে না:

perl -ne 'print unless $_ eq $k; $k=$_ if $.==1; 

-nপতাকা, তার ইনপুট ফাইল উপর লুপ Perl বলে প্রতিটি লাইন সংরক্ষণ $_$k=$_ if $.==1;সংরক্ষণ প্রথম লাইন ( $.লাইন সংখ্যা, তাই $.==1শুধুমাত্র 1 ম লাইন সত্য বলে ধরে নেব) হিসেবে $kprint unless $k eq $_কপি করে প্রিন্ট বর্তমান লাইন যদি এটা একই সংরক্ষিত হয় না $k

বিকল্পভাবে, একই জিনিস এতে awk:

awk '$0!=x;(NR==1){x=$0}' file 

এখানে, আমরা পরীক্ষা কিনা বর্তমান লাইন কি পরিবর্তনশীল সংরক্ষিত হয় হিসাবে একই x। যদি পরীক্ষাটি $0!=xসত্য হিসাবে মূল্যায়ন করে (যদি বর্তমান লাইনটি $0একই হয় না x) তবে লাইনটি মুদ্রণ করা হবে কারণ সত্যিকারের এক্সপ্রেশনগুলিতে অ্যাডকের জন্য ডিফল্ট ক্রিয়াটি মুদ্রণ করা। প্রথম লাইনটি ( NR==1) হিসাবে সংরক্ষণ করা হয়েছে x। যেহেতু বর্তমান লাইনটি মেলে কিনা তা যাচাই করার পরে xএটি করা হয়েছে, এটি প্রথম লাইনেও মুদ্রিত হবে তা নিশ্চিত করে।


আমি প্রথম লাইনের ধারণাটি না জানার কারণে এটি এটি আপনার সরঞ্জামবাক্সের জন্য একটি সাধারণ স্ক্রিপ্ট তৈরি করে।
মার্ক স্টুয়ার্ট

1
এই awk পদ্ধতিটি স্বতন্ত্র লাইনে প্রতি একটি খালি / মিথ্যা অ্যারে এন্ট্রি তৈরি করে; 4M লাইনগুলির জন্য যদি সমস্ত আলাদা (Q থেকে পরিষ্কার নয়) এবং মোটামুটি সংক্ষিপ্ত (তাই প্রদর্শিত হয়) এটি সম্ভবত ঠিক আছে তবে আরও বেশি বা দীর্ঘতর লাইন থাকলে এটি ছিটকে যেতে পারে বা মারা যেতে পারে। !($0 in a)এটি তৈরি না করে এবং এড়ানো এড়ানোর পরীক্ষা করে দেয়, বা '$0!=x; NR==1{x=$0}''NR==1{x=$0;print} $0!=x'
অ্যাডক আপনার কাছে পার্লের

1
@ dave_thompson_085 যেখানে প্রতি লাইন একটি অ্যারে তৈরি করা হয়? মানে !a[$0]? কেন এটি একটি এন্ট্রি তৈরি করবে a?
টেরডন

1
কারণ এটি কীভাবে কাজ করে; দেখতে gnu.org/software/gawk/manual/html_node/... বিশেষ করে "নোট"।
dave_thompson_085

1
@ dave_thompson_085 ভাল আমি জালিয়াতি করা হবে! ধন্যবাদ, আমি এটি সম্পর্কে সচেতন ছিলাম না। এখনই স্থির।
টেরডন

4

এডাব্লুকে এই জাতীয় উদ্দেশ্যগুলির জন্য একটি খুব শালীন সরঞ্জাম। এখানে কোডের নমুনা রান:

$ awk 'NR == 1 {print} NR != 1 && $0!~/ID  Data1  Data2/' rmLines.txt | head -n 10                                
ID  Data1  Data2
1    100    100
     100    200
3    200    100
1    100    100
     100    200
3    200    100
1    100    100
     100    200
3    200    100

ভাঙ্গা :

  • NR == 1 {print} টেক্সট ফাইলের প্রথম লাইন মুদ্রণ করতে আমাদের বলুন
  • NR != 1 && $0!~/ID Data1 Data2/ লজিকাল অপারেটর &&AWK কে 1 টির সমান নয় এমন লাইন প্রিন্ট করতে বলে ID Data1 Data2{print}অংশের অভাব নোট করুন ; যদি কোন পরীক্ষার শর্তটি সত্য হিসাবে মূল্যায়ন করা হয় তবে এটি লাইন প্রিন্ট করা হবে বলে ধরে নেওয়া হয়।
  • | head -n 10কেবলমাত্র প্রথম 10 লাইনে আউটপুট সীমিত করার জন্য এটি একটি ক্ষুদ্র সংযোজন। AWKঅংশটি নিজেই প্রাসঙ্গিক নয়, কেবল ডেমো উদ্দেশ্যে ব্যবহার করা হয়।

আপনি যদি কোনও ফাইলটিতে এটি চান, কমান্ডের > newFile.txtশেষে সংযোজন করে কমান্ডের আউটপুটটিকে পুনঃনির্দেশ করুন , এরকম:

awk 'NR == 1 {print} NR != 1 && $0!~/ID  Data1  Data2/' rmLines.txt > newFile.txt

এটা কিভাবে ধরে? খুব ভাল আসলে:

$ time awk 'NR == 1 {print} NR != 1 && $0!~/ID  Data1  Data2/' rmLines.txt > /dev/null                            
    0m3.60s real     0m3.53s user     0m0.06s system

সাইড নোট

উত্পন্ন নমুনা ফাইলটি এক থেকে দশ মিলিয়ন লুপিংয়ের জন্য এবং আপনার ফাইলের প্রথম চারটি লাইন মুদ্রণের জন্য করা হয়েছিল (সুতরাং 4 লাইন গুণ কয়েক মিলিয়ন 4 মিলিয়ন লাইনের সমান), যা 0.09 সেকেন্ড সময় নিয়েছিল।

awk 'BEGIN{ for(i=1;i<=1000000;i++) printf("ID  Data1  Data2\n1    100    100\n     100    200\n3    200    100\n");  }' > rmLines.txt

মনে রাখবেন যে ID Data1 Data2 fooএটি শিরোনামের মতো নয় এমন লাইনগুলিও মুদ্রণ করবে (এই ক্ষেত্রে কোনও পার্থক্য আনার সম্ভাবনা নেই, তবে আপনি কখনই জানেন না)।
টেরডন

@terdon হ্যাঁ, ঠিক আছে। ওপি অবশ্য তাদের কেবল একটি প্যাটার্ন নির্দিষ্ট করেছে যা তারা মুছে ফেলতে চায় এবং তার উদাহরণটি এটি সমর্থন করে বলে মনে হয়
সের্গেই কোলডিয়াজহনি

3

অজানা, যে কোনও শিরোনামকে স্বয়ংক্রিয়ভাবে মানিয়ে নেওয়া:

awk '( FNR == 1) {header=$0;print $0;}
     ( FNR > 1) && ($0 != header) { print $0;}'  file1  file2 ....

অর্থাত্, প্রথম লাইনে শিরোনামটি পান এবং এটি মুদ্রণ করুন এবং পরবর্তী শিরোনামটি ডিফলার থেকে সেই শিরোনামটি মুদ্রিত হবে।

বর্তমান ফাইলটিতে এফএনআর = রেকর্ডের সংখ্যা, যাতে আপনার একাধিক ফাইল থাকতে পারে এবং সেগুলির প্রতিটিতে এটি একই কাজ করবে।


2

সম্পূর্ণতার স্বার্থে, পার্ট সলিউশন আইএমও @terdon যে পরিমাণ দিয়েছেন তার চেয়ে কিছুটা মার্জিত:

perl -i -p -e 's/^ID.*$//s if $. > 1' file

1
আহ, তবে আমার পুরো বিষয়টি প্যাটার্নটি নির্দিষ্ট করার প্রয়োজন এড়ানো এবং পরিবর্তে এটি প্রথম পংক্তিটি থেকে পড়তে হয়েছিল। আপনার পদ্ধতির সাহায্যে শুরু হওয়া কোনও লাইন মুছে ফেলা হবে ID। আপনার কোনও গ্যারান্টি নেই যে এটি রাখা উচিত লাইনগুলি মুছে ফেলবে না। যেহেতু আপনি কমনীয়তা নিয়ে এসেছেন, gআপনি যদি ব্যবহার করেন ^এবং করেন তবে তা অর্থহীন $। প্রকৃতপক্ষে, আপনার সমস্ত বিকল্পগুলি m///এখানে ব্যার্থ ব্যতীত s; আপনি যে বৈশিষ্ট্যগুলি ব্যবহার করছেন না সেগুলি তারা সক্রিয় করে। সুতরাং $, s/^ID.*//sএকই জিনিস করতে হবে।
টেরডন

@terdon, যথেষ্ট ন্যায্য। তোমার সর্বজনীন!
কেউববুফিটোইচিজ

2

এই প্রশ্নটিকে কিছুটা পিছনে ঠেকানোর জন্য ... দেখে মনে হচ্ছে আপনার ইনপুটটি নিজেই বেশ কয়েকটি টিএসভি ফাইল একসাথে ক্যাট করার ফলাফল। যদি আপনি আপনার প্রসেসিং পাইপলাইনের কোনও পদক্ষেপের ব্যাক আপ করতে পারেন (যদি আপনি তার মালিক হন বা যারা করেন তাদের সাথে কথা বলতে পারেন) তবে আপনি প্রথমে ডেটা যুক্ত করার জন্য শিরোনাম-সচেতন একটি সরঞ্জাম ব্যবহার করতে পারেন এবং এর ফলে সমস্যাটি দূর করতে পারেন অতিরিক্ত শিরোনামের লাইনগুলি সরান।

উদাহরণস্বরূপ, মিলার ব্যবহার :

$ cat f1.tsv
ID  Data1 Data2
1 100 100
2 100 200
3 200 100
$ cat f2.tsv
ID  Data1 Data2
4 100 100
$ cat f3.tsv
ID  Data1 Data2
5 200 200

$ cat f1.tsv f2.tsv  f3.tsv
ID  Data1 Data2
1 100 100
2 100 200
3 200 100
ID  Data1 Data2
4 100 100
ID  Data1 Data2
5 200 200

$ mlr --tsvlite cat f1.tsv f2.tsv  f3.tsv
ID  Data1 Data2
1 100 100
2 100 200
3 200 100
4 100 100
5 200 200

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