গ্রেপ দিয়ে একটি আউটপুট কীভাবে দুটি ফাইলে বিভক্ত করবেন?


14

আমার একটি স্ক্রিপ্ট আছে mycommand.shযা আমি দু'বার চালাতে পারি না। আমি আউটপুট দুটি ভিন্ন ফাইলগুলিতে বিভক্ত করতে চাই একটি ফাইল যা একটি রেইজেক্সের সাথে মেলে এমন একটি ফাইল এবং একটি ফাইল যা একটি রেজেক্সের সাথে মেলে না। আমি যা পেতে চাই তা মূলত এরকম কিছু:

./mycommand.sh | grep -E 'some|very*|cool[regex].here;)' --match file1.txt --not-match file2.txt

আমি জানি যে আমি আউটপুটটিকে কেবল একটি ফাইলে পুনর্নির্দেশ করতে পারি এবং তারপরে -v বিকল্পের সাথে এবং বিযুক্ত দুটি ভিন্ন গ্রেপগুলিতে এবং আউটপুটটিকে দুটি পৃথক ফাইলে পুনর্নির্দেশ করতে পারি। তবে আমি খুব ভাবছিলাম যে এটি যদি একটি গ্রিপ দিয়ে করা সম্ভব হয়।

সুতরাং, আমি একটি লাইনে যা চাই তা অর্জন করা সম্ভব?

উত্তর:


20

এটি সম্পাদন করার জন্য অনেকগুলি উপায় রয়েছে।

অজানা ব্যবহার করা হচ্ছে

নিম্নলিখিত coolregexফাইল 1 এর সাথে মেলে যে কোনও লাইন প্রেরণ করে । অন্যান্য সমস্ত লাইন ফাইল 2 এ যায়:

./mycommand.sh | awk '/[coolregex]/{print>"file1";next} 1' >file2

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

  1. /[coolregex]/{print>"file1";next}

    নিয়মিত প্রকাশের সাথে মেলে যে কোনও লাইন coolregexমুদ্রণ করা হয় file1। তারপরে, আমরা সমস্ত অবশিষ্ট কমান্ডগুলি এড়িয়ে যাই এবং nextলাইনে শুরু করতে লাফিয়ে যাই ।

  2. 1

    অন্যান্য সমস্ত লাইন stdout পাঠানো হয়। 1প্রিন্ট-দ্য লাইনটির জন্য awk এর ক্রিপ্টিক শর্টহ্যান্ড।

একাধিক স্ট্রিমে বিভক্ত হওয়াও সম্ভব:

./mycommand.sh | awk '/regex1/{print>"file1"} /regex2/{print>"file2"} /regex3/{print>"file3"}'

প্রক্রিয়া বিকল্প ব্যবহার করে

এটি অ্যাডক সমাধানের মতো মার্জিত নয় তবে সম্পূর্ণতার জন্য আমরা প্রক্রিয়া প্রতিস্থাপনের সাথে একত্রে একাধিক গ্রেপ ব্যবহার করতে পারি:

./mycommand.sh | tee >(grep 'coolregex' >File1) | grep -v 'coolregex' >File2

আমরা একাধিক স্ট্রিমগুলিতে বিভক্তও হতে পারি:

./mycommand.sh | tee >(grep 'coolregex' >File1) >(grep 'otherregex' >File3) >(grep 'anotherregex' >File4) | grep -v 'coolregex' >File2

ওহ ঠান্ডা! কেবল ফাইল 2 এর পরিবর্তে অন্য এডক না করেও এটি বেশ কয়েকটি ফাইলে বিভক্ত করা সম্ভব? আমি এমনভাবে বোঝাতে চাইছি যে রেজিক্সগুলি উদাহরণস্বরূপ ওভারল্যাপ করতে পারে।
ইউকশিমা হক্কে

1
@ অ্যারান হ্যাঁ, অজানা খুব নমনীয়। ঠিক কীভাবে এটি কী করে তা নির্ভর করে কীভাবে রেজেক্সগুলি ওভারল্যাপ হয় on
1024

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

1
@ আমি উভয় পদ্ধতির একাধিক স্ট্রিম সহ উত্তর উদাহরণগুলিতে যুক্ত করেছি।
1024

8
sed -n -e '/pattern_1/w file_1' -e '/pattern_2/w file_2' input.txt

w filename - ফাইলের নামটিতে বর্তমান প্যাটার্ন স্পেস লিখুন।

আপনি সব ম্যাচিং লাইনে যেতে চান file_1এবং সব অ-মিল লাইনে file_2, আপনি করতে পারেন:

sed -n -e '/pattern/w file_1' -e '/pattern/!w file_2' input.txt

অথবা

sed -n '/pattern/!{p;d}; w file_1' input.txt > file_2

ব্যাখ্যা

  1. /pattern/!{p;d};
    • /pattern/!- প্রত্যাখ্যান - যদি একটি লাইনে না থাকে pattern
    • p - বর্তমান প্যাটার্ন স্পেস মুদ্রণ করুন।
    • d- প্যাটার্ন স্পেস মুছুন। পরবর্তী চক্র শুরু করুন।
    • সুতরাং, যদি কোনও লাইনে প্যাটার্ন না থাকে তবে এটি এই রেখাটিকে স্ট্যান্ডার্ড আউটপুটে মুদ্রণ করে এবং পরবর্তী লাইনটি বেছে নেয়। স্ট্যান্ডার্ড আউটপুট file_2আমাদের ক্ষেত্রে পুনঃনির্দেশিত হয় । sedস্ক্রিপ্টটির পরবর্তী অংশটি w file_1পৌঁছায় না while
  2. w file_1- যদি একটি লাইন প্যাটার্ন রয়েছে, /pattern/!{p;d};অংশ এড়ানো হয় (কারণ এটি কার্যকর শুধুমাত্র যখন প্যাটার্ন মেলে না) এবং, এইভাবে, এই লাইন চলে যায় file_1

আপনি কি দয়া করে শেষ সমাধানটিতে আরও কিছু ব্যাখ্যা যুক্ত করতে পারেন?
ইউকশিমা হুকসাই

@aran ব্যাখ্যা যুক্ত হয়েছে। কমান্ডটিও সংশোধন করা হয়েছে - file_1এবং file_2সঠিক ক্রমে সরিয়ে নেওয়া হয়েছে।
মিনিম্যাক্স

0

আমি sedসমাধানটি পছন্দ করেছি যেহেতু এটি বাশিজমের উপর নির্ভর করে না এবং একই পাদদেশে আউটপুট ফাইলগুলি ব্যবহার করে। আফাইক, ইউনিক্সের এমন কোনও সরঞ্জাম নেই যা আপনি যা করতে চান তা তাই আপনাকে নিজে প্রোগ্রাম করার দরকার আছে। যদি আমরা সুইস সেনাবাহিনীর ছুরির পদ্ধতির বিষয়টি পরিত্যাগ করি তবে আমরা স্ক্রিপ্টিংয়ের যে কোনও ভাষা (পার্ল, পাইথন, নোডজেএস) ব্যবহার করতে পারি।

নোডজেএস-এ এটি করা হবে

  #!/usr/bin/env node

  const fs = require('fs');
  const {stderr, stdout, argv} = process;

  const pattern = new RegExp(argv[2] || '');
  const yes = argv[3] ? fs.createWriteStream(argv[3]) : stdout;
  const no = argv[4] ? fs.createWriteStream(argv[4]) : stderr;

  const out = [no, yes];

  const partition = predicate => e => {
    const didMatch = Number(!!predicate(e));
    out[didMatch].write(e + '\n');
  };

  fs.readFileSync(process.stdin.fd)
    .toString()
    .split('\n')
    .forEach(partition(line => line.match(pattern)));

ব্যবহারের উদাহরণ

# Using designated files
./mycommand.sh | partition.js pattern file1.txt file2.txt

# Using standard output streams
./partition.js pattern > file1.txt 2> file2.txt

0

যদি আপনি পাইথন এবং একটি আলাদা নিয়মিত এক্সপ্রেশন সিনট্যাক্স ব্যবহারে আপত্তি না পান:

#!/usr/bin/env python3
import sys, re

regex, os1, os2 = sys.argv[1:]
regex = re.compile(regex)
with open(os1, 'w') as os1, open(os2, 'w') as os2:
    os = (os1, os2)
    for line in sys.stdin:
        end = len(line) - line.endswith('\n')
        os[regex.search(line, 0, end) is not None].write(line)

ব্যবহার

./match-split.py PATTERN FILE-MATCH FILE-NOMATCH

উদাহরণ

printf '%s\n' foo bar baz | python3 match-split.py '^b' b.txt not-b.txt
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.