কোনও ফাইলের কয়েকটি বিভাগ ফিল্টার বা পাইপ করুন


14

আমার কয়েকটি বিভাগের সাথে একটি ইনপুট ফাইল রয়েছে যা শুরু এবং শেষ ট্যাগগুলির সাথে চিহ্নিত করা হয়, উদাহরণস্বরূপ:

line A
line B
@@inline-code-start
line X
line Y
line Z
@@inline-code-end
line C
line D

আমি এই ফাইলটিতে এমন একটি রূপান্তর প্রয়োগ করতে চাই যে এক্স, ওয়াই, জেড কিছু কমান্ডের মাধ্যমে ফিল্টার করা হয় ( nlউদাহরণস্বরূপ), তবে বাকী রেখাগুলি অপরিবর্তিত হয়ে যায়। লক্ষ্য করুন যে nl(সংখ্যা রেখাগুলি) রেখাগুলি জুড়ে রাজ্যকে একত্রিত করে, তাই এটি কোনও স্থির রূপান্তর নয় যা এক্স, ওয়াই, জেডের প্রতিটি লাইনে প্রয়োগ করা হচ্ছে। ( সম্পাদনা করুন : এটি চিহ্নিত করা হয়েছিল nlযে এমন মোডে কাজ করতে পারে যা জমে থাকা রাষ্ট্রের প্রয়োজন হয় না, তবে আমি nlপ্রশ্নকে সহজ করার জন্য উদাহরণ হিসাবে ব্যবহার করছি reality বাস্তবে আদেশটি একটি আরও জটিল কাস্টম স্ক্রিপ্ট I আমি যা দেখছি সত্যই কারণ কোনও ইনপুট ফাইলের উপধারাতে একটি স্ট্যান্ডার্ড ফিল্টার প্রয়োগ করার সমস্যার সাধারণ সমাধান )

ফলাফলটি দেখতে হবে:

line A
line B
     1 line X
     2 line Y
     3 line Z
line C
line D

ফাইলটিতে এমন বেশ কয়েকটি বিভাগ থাকতে পারে যা রূপান্তরের প্রয়োজন।

আপডেট 2 আমি আরও একটি বিভাগ থাকলে উদাহরণস্বরূপ কি হবে তা আমি প্রাথমিকভাবে নির্দিষ্ট করেছিলাম না:

line A
line B
@@inline-code-start
line X
line Y
line Z
@@inline-code-end
line C
line D
 @@inline-code-start
line L
line M
line N
@@inline-code-end

আমার প্রত্যাশাটি হ'ল রাষ্ট্রটি কেবলমাত্র একটি নির্দিষ্ট বিভাগের মধ্যে বজায় রাখা দরকার:

line A
line B
     1 line X
     2 line Y
     3 line Z
line C
line D
     1 line L
     2 line M
     3 line N

তবে, আমি মনে করি যে সমস্যাটিকে রাষ্ট্রটিকে বিভাগের আওতাধীন রাখা আবশ্যক হিসাবে ব্যাখ্যা করা বৈধ এবং অনেকগুলি ক্ষেত্রে কার্যকর।

শেষ আপডেট 2

আমার প্রথম চিন্তাটি হল একটি সরল রাষ্ট্রীয় মেশিন তৈরি করা যা আমরা কোন বিভাগে আছি তা ট্র্যাক করে:

#!/usr/bin/bash
while read line
do
  if [[ $line == @@inline-code-start* ]]
  then
    active=true
  elif [[ $line == @@inline-code-end* ]]
  then
    active=false
  elif [[ $active = true ]]
  then
    # pipe
  echo $line | nl
  else
    # output
    echo $line
  fi
done

যা দিয়ে আমি চালাচ্ছি:

cat test-inline-codify | ./inline-codify

প্রতিটি কল nlস্বতন্ত্র হওয়ায় এটি কাজ করে না , সুতরাং লাইন নম্বরগুলি বৃদ্ধি না করে:

line A
line B
     1  line X
     1  line Y
     1  line Z
line C
line D

আমার পরের চেষ্টাটি ছিল একটি ফিফো ব্যবহারের:

#!/usr/bin/bash
mkfifo myfifo
nl < myfifo &
while read line
do
  if [[ $line == @@inline-code-start* ]]
  then
    active=true
  elif [[ $line == @@inline-code-end* ]]
  then
    active=false
  elif [[ $active = true ]]
  then
    # pipe
    echo $line > myfifo
  else
    # output
    echo $line
  fi
done
rm myfifo

এটি সঠিক আউটপুট দেয় তবে ভুল ক্রমে:

line A
line B
line C
line D
     1  line 1
     2  line 2
     3  line 3

সম্ভবত কিছু কিছু ক্যাশে চলছে।

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


nlরাষ্ট্র জমে আছে না । লুক এ nl -dএবং আপনার চেকে man/ infoতথ্যের জন্য পৃষ্ঠাগুলি nl'র অধ্যায় বিভেদক
মাইকসার্ভ

এনএল একটি উদাহরণ। আমার ক্ষেত্রে আমি এনএল পরিবর্তে একটি কাস্টম স্ক্রিপ্ট চালাচ্ছি।
জেমস স্ক্রিভেন

সেক্ষেত্রে আপনার স্ক্রিপ্টটি কী করছে তা দয়া করে পরিষ্কার করুন।
টেরডন

আমি প্রশ্নে স্পষ্ট করেছিলাম যে আমি কেবল nlউদাহরণ ফিল্টার হিসাবে ব্যবহার করছি । আমি ভেবেছিলাম ফিল্টারটি ঠিক কী করছে তার বিশদটি চকচকে করে প্রশ্নটি সহজ করে দেবে, তবে আমি সম্ভবত আরও বিভ্রান্তি সৃষ্টি করেছি। প্রকৃতপক্ষে, আমি একটি বাড়ির-বর্ধিত স্থির ব্লগ জেনারেটরের জন্য একটি কোড হাইলাইটারটির মাধ্যমে সাবসেকশনটি ফিল্টার করছি। এই মুহূর্তে আমি gnu ব্যবহার করছি source-highlight, তবে এটি পরিবর্তন হতে পারে এবং আমি আরও ফিল্টার যুক্ত করতে পারি, যেমন একটি ফর্ম্যাটরও।
জেমস স্ক্রিভেন

উত্তর:


7

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


nl

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

অন্য একটি বিভাগ অন্তর্ভুক্ত করার জন্য আমি এটি আপনার উদাহরণ পরিবর্তন করেছি ./infile। সুতরাং এটির মতো দেখাচ্ছে:

line A
line B
@@inline-code-start
line X
line Y
line Z
@@inline-code-end
line C
line D
@@start
line M
line N
line O
@@end

তারপরে আমি নীচে দৌড়েছি:

sed 's/^@@.*start$/@@@@@@/
     s/^@@.*end$/@@/'  <infile |
nl -d@@ -ha -bn -w1

nlলজিকাল পৃষ্ঠাগুলি জুড়ে রাজ্যে একত্রিত হতে বলা যেতে পারে , তবে এটি ডিফল্টরূপে হয় না। পরিবর্তে এটি শৈলী এবং বিভাগ অনুসারে এর ইনপুটটির রেখাটি সংখ্যায়িত করবে । সুতরাং -haসমস্ত শিরোনামের লাইন সংখ্যা এবং -bnমানে কোনও বডি লাইন - যেহেতু এটি কোনও শরীরের অবস্থায় শুরু হয় ।

যতক্ষণ না আমি এটি শিখেছি আমি nlকোনও ইনপুট ব্যবহার করতাম , তবে বুঝতে পারার পরে যে nlএটির ডিফল্ট -dএলিমিটার অনুসারে আউটপুটটি বিকৃত হতে পারে \:আমি এর সাথে আরও সতর্কতা অবলম্বন করতে শিখেছি এবং grep -nF ''পরিবর্তে অনির্ধারিত ইনপুট ব্যবহার করতে শুরু করেছি । তবে সেই দিনটি শিখানো আরেকটি শিক্ষাটি ছিল যে nlএটি অন্যান্য ক্ষেত্রে যেমন খুব কার্যকরভাবে প্রয়োগ করা যেতে পারে - যেমন এই - আপনি যদি কেবল তার ইনপুটটিকে কিছুটা সংশোধন করেন - যেমন আমি sedউপরের সাথে করি ।

আউটপুট

  line A
  line B

1       line X
2       line Y
3       line Z

  line C
  line D

1       line M
2       line N
3       line O

এখানে আরও কিছু nl- আপনি উপরে লক্ষ করেছেন কীভাবে সমস্ত রেখাগুলি বাদে শূন্যস্থান দিয়ে শুরু হয়? nlসংখ্যার রেখাগুলি যখন এটি প্রতিটিের মাথার মধ্যে একটি নির্দিষ্ট সংখ্যক অক্ষর সন্নিবেশ করে। এই রেখাগুলির জন্য এটি সংখ্যা নয় - শূন্যস্থানগুলিও - এটি সর্বদা -wশনাক্তকরণহীন -sলাইনের শীর্ষে ফাঁকা স্থানগুলি ( আইডথ গণনা + ইপারেটর লেন) সন্নিবেশ করে ইন্ডেন্টের সাথে মেলে । এটি আপনাকে সংখ্যাযুক্ত বিষয়বস্তুটির সাথে সংখ্যার বিষয়বস্তুর সাথে তুলনা করে - এবং অল্প প্রচেষ্টা দিয়ে পুনরুত্পাদন করতে দেয়। যখন আপনি বিবেচনা করেন যে nlএটির জন্য আপনার ইনপুটটি যৌক্তিক বিভাগগুলিতে বিভক্ত করবে এবং আপনি -sপ্রতিটি লাইনটির শীর্ষে নির্বিচারে ট্র্যাংগুলি সন্নিবেশ করতে পারেন , তার আউটপুটটি পরিচালনা করা খুব সহজ হয়ে যায়:

sed 's/^@@.*start$/@@@@@@/
     s/^@@.*end/@@/; t
     s/^\(@@\)\{1,3\}$/& /' <infile |
nl -d@@ -ha -bn -s' do something with the next line!
'

উপরের প্রিন্টগুলি ...

                                        line A
                                        line B

 1 do something with the next line!
line X
 2 do something with the next line!
line Y
 3 do something with the next line!
line Z

                                        line C
                                        line D

 1 do something with the next line!
line M
 2 do something with the next line!
line N
 3 do something with the next line!
line O

গনুহ sed

যদি nlআপনার টার্গেট আবেদন নয়, তারপর একটি গনুহ sedকরতে eআপনি একটি ম্যাচ উপর নির্ভর করে একটি অবাধ শেল কমান্ড xecute।

sed '/^@@.*start$/!b
     s//nl <<\\@@/;:l;N
     s/\(\n@@\)[^\n]*end$/\1/
Tl;e'  <infile

উপরের sedপ্যাটার্ন স্পেসে ইনপুট সংগ্রহ করে যতক্ষণ না এটি সফলভাবে প্রতিস্থাপনের পাসটি পাস করতে Tএবং আবেলের bপিছনে :lপাল্লা দেওয়া বন্ধ করে দেয় । এটি যখন হয়ে যায়, এটি এর eবাকী সমস্ত প্যাটার্ন-স্পেসের জন্য এখানে-নথি nlহিসাবে উপস্থাপিত হয়ে ইনপুট দিয়ে xecutes করে <<

কর্মপ্রবাহ এইরকম:

  1. /^@@.*start$/!b
    • যদি কোনো ^সমগ্র লাইন $নেই !না /মেলে /উপরে প্যাটার্ন, তাহলে এটি করা হয় bস্ক্রিপ্টের বাইরে ranched এবং autoprinted - তাই এই বিন্দু থেকে আমরা কেবল যা প্যাটার্ন সঙ্গে শুরু লাইনের সিরিজের সঙ্গে কাজ করছে।
  2. s//nl <<\\@@/
    • খালি s//ক্ষেত্রটি /শেষের ঠিকানাটির sedসাথে মিলের চেষ্টা করার জন্য দাঁড়িয়েছে - সুতরাং এই কমান্ডটি পরিবর্তে পুরো @@.*startলাইনটিকে প্রতিস্থাপন করবে nl <<\\@@
  3. :l;N
    • :কমান্ড একটি শাখা ট্যাগ সংজ্ঞায়িত - এখানে আমি এক নামে সেট :lআবেল। NEXT কমান্ড পাশে একটি দ্বারা অনুসরণ প্যাটার্ন স্থান ইনপুট লাইন appends \newline অক্ষর। \nকোনও sedপ্যাটার্ন স্পেসে ই- লাইন পাওয়ার কয়েকটি উপায়গুলির মধ্যে এটি - \nইওলাইন চরিত্রটি কোনও ডেরের কাছে নিশ্চিতভাবে ডিলিমিটার, sedযিনি এটি কিছুক্ষণ করছেন।
  4. s/\(\n@@\)[^\n]*end$/\1/
    • এই s///প্রতিবন্ধকতা কেবলমাত্র কোনও শুরুর মুখোমুখি হওয়ার পরে এবং শুধুমাত্র শেষের লাইনের প্রথম নিম্নলিখিত ইভেন্টে সফল হতে পারে । এটি কেবলমাত্র একটি প্যাটার্ন স্পেসে কাজ করবে যেখানে প্যাটার্ন স্পেসের একেবারে শেষ চিহ্নিত করে \nঅবিলম্বে চূড়ান্ত ewline অনুসরণ করা হবে। যখন এটি কাজ করে, এটা দিয়ে পুরো মিলেছে স্ট্রিং প্রতিস্থাপন প্রথম গ্রুপ , বা ।@@.*end$\1\(\)\n@@
  5. Tl
    • Tকোন লেবেলে হল কমান্ড শাখা (যদি প্রদত্ত) যদি একটি সফল প্রতিস্থাপন শেষ সময় একটি ইনপুট লাইন প্যাটার্ন মহাকাশ টানা ছিল যেহেতু ঘটেছে করেনি (আমি W / কি হিসাবে N) । এর অর্থ হ'ল প্রতিবারের মতো \newline প্যাটার্ন স্পেসে যুক্ত হবে যা আপনার শেষ ডিলিমিটারের সাথে মেলে না, Tইস্ট কমান্ড ব্যর্থ হয় এবং শাখাগুলি :lহাবলে ফিরে যায় , যার ফলশ্রুতি এক্সট লাইনটি sedটানতে এবং Nসফল হওয়া পর্যন্ত লুপ করে।
  6. e

    • যখন শেষ ম্যাচের বিকল্পটি সফল হয় এবং স্ক্রিপ্টটি কোনও ব্যর্থ স্থানে ফিরে আসে না T, তখন sedএই eআদেশটি xecute করবে l:

      nl <<\\@@\nline X\nline Y\nline Z\n@@$

দেখতে দেখতে শেষ লাইনটি সম্পাদনা করে আপনি নিজের জন্য এটি দেখতে পারেন Tl;l;e

এটি প্রিন্ট করে:

line A
line B
     1  line X
     2  line Y
     3  line Z
line C
line D
     1  line M
     2  line N
     3  line O

while ... read

এটি করার একটি শেষ উপায় এবং সম্ভবত সবচেয়ে সহজ উপায় হ'ল while readলুপ ব্যবহার করা , তবে সঙ্গত কারণে। শেলটি - (বিশেষত একটি bashশেল) - সাধারণত প্রচুর পরিমাণে বা অবিচলিত স্ট্রিমগুলিতে ইনপুট পরিচালনা করার ক্ষেত্রে বেশ অদ্ভুত। এটিও বোধগম্য হয় - শেলের কাজ হ'ল অক্ষর অনুসারে ইনপুট চরিত্রটি পরিচালনা করা এবং বড় কমান্ডগুলি পরিচালনা করতে পারে এমন অন্যান্য কমান্ড কল করা।

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

সিঙ্ক ইনপুট প্রক্রিয়াজাতকরণের জন্য কেউ কীভাবে read এবং অন্যান্য আদেশ ব্যবহার করতে পারে তার উদাহরণ এখানে রয়েছে :

while   IFS= read -r line        &&
case    $line in (@@*start) :;;  (*)
        printf %s\\n "$line"
        sed -un "/^@@.*start$/q;p";;
esac;do sed -un "/^@@.*end$/q;=;p" |
        paste -d: - -
done    <infile

প্রতিটি পুনরাবৃত্তির জন্য প্রথম যেটি ঘটে তা হ'ল readএকটি লাইনে টান। যদি এটি সফল হয় তবে এর অর্থ লুপটি এখনও ইওএফ-তে আঘাত করে নি এবং তাই caseএটির সাথে একটি শুরু ডিলিমিটারের সাথে মেলে doব্লকটি তত্ক্ষণাত কার্যকর করা হয় exec অন্যথায়, এটি printfমুদ্রণ এবং বলা হয়।$linereadsed

sedহবে pনা হওয়া পর্যন্ত encounters যে লাইন দ্রণ শুরু যখন এটি - মার্কার qসম্পূর্ণভাবে ইনপুট uits। -uNbuffered সুইচ গনুহ জন্য প্রয়োজনীয় sedকারণ এটি বরং সাগ্রহে অন্যথায় বাফার করতে পারেন, কিন্তু - বৈশিষ্ট অনুযায়ী - অন্য POSIX sedগুলি কোনো বিশেষ বিবেচনা ছাড়া কাজ করা উচিত - তাই যতদিন <infileএকটি নিয়মিত ফাইল।

যখন প্রথম sed qইউটিস হয়, শেলটি লুপটির doব্লকটি সম্পাদন করে - যা অন্যটিকে কল করে sedযা প্রতিটি লাইন প্রান্তিক না হওয়া পর্যন্ত শেষ করে । এটি তার আউটপুটটি পাইপ করে paste, কারণ এটি প্রতিটি নিজস্ব লাইনে লাইন নম্বর প্রিন্ট করে। এটার মত:

1
line M
2
line N
3
line O

pasteতারপরে :অক্ষরগুলিতে এগুলি একত্রিত করে এবং পুরো আউটপুটটি দেখতে দেখতে:

line A
line B
1:line X
2:line Y
3:line Z
line C
line D
1:line M
2:line N
3:line O

এগুলি কেবল উদাহরণস্বরূপ - পরীক্ষায় বা ব্লকগুলিতে যে কোনও কিছুই করা যেতে পারে, তবে প্রথম ইউটিলিটি অবশ্যই খুব বেশি ইনপুট গ্রহণ করবে না।

জড়িত সমস্ত ইউটিলিটি একই ইনপুট পড়ুন - এবং ফলাফলগুলি মুদ্রণ করুন - প্রত্যেকে নিজের পরিবর্তে। জিনিস এই ধরনের আসে পেতে কঠিন হতে পারে - কারণ বিভিন্ন ইউটিলিটি অন্যদের তুলনায় বেশি বাফার হবে - কিন্তু আপনি সাধারণত নির্ভর করতে পারেন dd, headএবং sedডান জিনিস করতে (যদিও, গনুহ জন্য sed, আপনি CLI-সুইচ প্রয়োজন) এবং আপনার সর্বদা নির্ভর করতে সক্ষম হওয়া উচিত read- কারণ এটি প্রকৃতির দ্বারা খুব ধীর । এবং এই কারণেই উপরের লুপটি প্রতি ইনপুট ব্লকটিকে কেবল একবারে কল করে।


sedআপনার দেওয়া দ্বিতীয় উদাহরণটি আমি পরীক্ষা করেছিলাম এবং এটি কার্যকর হয় তবে সিনট্যাক্সটি ছাঁটাইতে আসলেই আমার খুব সমস্যা হয়। (আমার সিড বেশ দুর্বল এবং সাধারণত গুলি / সন্ধানী / প্রতিস্থাপন / জি এর মধ্যে সীমাবদ্ধ I'll আমি বসে বসে সত্যিকার অর্থে বুঝতে চেষ্টা করব))
জেমস স্ক্রিভেন

@ জেমসস্প্রিভেন - আমি এটির আরও ভালভাবে ব্যাখ্যা করার জন্য সম্পাদনা করেছি। যদি এটি সাহায্য না করে তবে আমাকে জানান। আমি কমান্ডটিও অনেক পরিবর্তন করেছি - এটি এখন ছোট, আরও বুদ্ধিমান টুকরোতে।
মাইকজার্ভ

4

একটি সম্ভাবনা ভিএম টেক্সট এডিটর দিয়ে এটি করা। এটি শেল কমান্ডের মাধ্যমে স্বেচ্ছাসেবী বিভাগগুলিকে পাইপ করতে পারে।

এটি করার একটি উপায় হ'ল লাইন সংখ্যাগুলি ব্যবহার করে :4,6!nl। এই প্রাক্তন কমান্ডটি 4-6 সমেত লাইনগুলিতে এনএল চালাবে, আপনার উদাহরণ ইনপুটটিতে আপনি যা চান তা অর্জন করবে।

আর একটি, আরও ইন্টারেক্টিভ উপায় হ'ল লাইন-নির্বাচন মোড (শিফট-ভি) এবং তীর কী বা অনুসন্ধান এবং তারপরে ব্যবহার করে উপযুক্ত লাইনগুলি নির্বাচন করা :!nl। আপনার উদাহরণ ইনপুট জন্য একটি সম্পূর্ণ কমান্ড ক্রম হতে পারে

/@@inline-code-start
jV/@@inline-code-end
k:!nl

এটি অটোমেশনের পক্ষে খুব উপযুক্ত নয় (উদাহরণস্বরূপ সেড ব্যবহারের উত্তরগুলি এর জন্য ভাল) তবে এক-অফ সম্পাদনাগুলির জন্য এটি 20-লাইনের শেলস্প্রিপ্ট অবলম্বন না করে খুব দরকারী।

আপনি যদি ভি (এম) এর সাথে পরিচিত না হন তবে আপনার খুব কমপক্ষে জানা উচিত যে এই পরিবর্তনগুলির পরে আপনি ফাইলটি সংরক্ষণ করে ব্যবহার করতে পারেন :wq


হ্যাঁ, ভিম দুর্দান্ত! তবে আমি এই ক্ষেত্রে স্ক্রিপ্টযোগ্য সমাধান খুঁজছি।
জেমস স্ক্রিভেন

@ জেমসস্প্রেইন, যে কেউ বলেন যে ভিম অপ্রতুলতার সাথে নির্ধারিতভাবে স্ক্রিপ্টযোগ্য নয়। প্রথমে একটি প্রকল্প ডিরেক্টরি তৈরি করুন এবং সেই ডিরেক্টরিতে আপনার হোম ডিরেক্টরি থেকে ভিআইএম এর সমস্ত প্রারম্ভিক ফাইলগুলি অনুলিপি করুন (ln -s যা আমরা পরিবর্তন করতে চলেছি .vimrc ব্যতীত সূক্ষ্মভাবে কাজ করে যা শব্দে ভরা হতে পারে) im ফাংশন সংজ্ঞা যুক্ত করুন যা নতুন .vimrc ফাইলটিতে কাজ করবে এবং তারপরে vim কে কল করবে HOME=$(pwd) vim -c 'call Mf()' f। আপনি যদি জার্গস ব্যবহার করে থাকেন তবে আপনার টিটিটি ক্ষতিগ্রস্থ করা থেকে বিরত রাখতে আপনি কোনও ডেডিকেটেড এক্সসার্ভারে জিভিআইএম ব্যবহার করতে চাইতে পারেন (ভিএনসি ভিডিও কার্ড স্বাধীন এবং এটি পর্যবেক্ষণ করা যেতে পারে)।
hildred

@ হিল্ডার্ড হ্ম্ম্ম্ম ... আমি কি ভিএম-র মাউস ক্লিকগুলি অনুকরণ করার জন্য [এক্সসেন্ডইভেন্ট] ( ট্রোনচে.com / gui / x / xlib / event-handling / XSendEvent.html ) ব্যবহার করতে পারি না ?
জেমস স্ক্রিভেন

2

আমি যে সহজ সমাধানটি ভাবতে পারি তা হ'ল ব্যবহার না nlকরে লাইনগুলি নিজেই গণনা করা:

#!/usr/bin/env bash
while read line
do
    if [[ $line == @@inline-code-start* ]]
    then
        active=true
    elif [[ $line == @@inline-code-end* ]]
    then
        active=false
    elif [[ $active = true ]]
    then
        ## Count the line number
        let num++;
        printf "\t%s %s\n" "$num" "$line"
    else
        # output
        printf "%s\n" "$line"
    fi
done

তারপরে আপনি এটিকে ফাইলটিতে চালান:

$ foo.sh < file
line A
line B
    1 line X
    2 line Y
    3 line Z
line C
line D

ধন্যবাদ টেরডন আমি প্রশ্নটি আপডেট করে আপডেট করেছিলাম যে আমি একটি ইনপুট সাবসেকশন ফিল্টার করার জন্য একটি জেনেরিক সমাধান খুঁজছি, বরং নম্বর লাইনগুলির নির্দিষ্ট উদাহরণ example সম্ভবত আরও ভাল উদাহরণ কমান্ড "ট্যাক" (বিপরীত লাইন) হতে পারে
জেমস স্ক্রিভেন

2

যদি আপনার লক্ষ্যটি একটি একক প্রক্রিয়া উদাহরণে পুরো কোড ব্লকটি প্রেরণ করা হয় তবে আপনি কোড ব্লকের শেষ না হওয়া পর্যন্ত আপনি লাইনগুলি সংগ্রহ করতে এবং পাইপিংয়ে বিলম্ব করতে পারেন:

#!/bin/bash

acc=""

while read line
do
  if [[ $line == @@inline-code-start* ]]
  then
    active=true
    acc=""
  elif [[ $line == @@inline-code-end* ]]
  then
    active=false
    # Act on entire block of code
    echo "${acc:1}" | nl  # Chops off first leading new-line character using ${VAR:1}
  elif [[ $active = true ]]
  then
    acc=$( printf "%s\n%s" "$acc" "$line" )
  else
    # output
    echo $line
  fi
done

এটি একটি ইনপুট ফাইলের জন্য নিম্নলিখিতটি উত্পন্ন করে যা পরীক্ষার কেসটি তিনবার পুনরায় পুনঃস্থাপন করে:

line A
line B
     1  line X
     2  line Y
     3  line Z
line C
line D
line A
line B
     1  line X
     2  line Y
     3  line Z
line C
line D
line A
line B
     1  line X
     2  line Y
     3  line Z
line C
line D

কোড ব্লক দিয়ে অন্য কিছু করার জন্য, যেমন বিপরীত এবং তারপরে সংখ্যাটি, কেবল অন্য কোনও কিছুর মাধ্যমে পাইপ করুন: echo -E "${acc:1}" | tac | nl । ফলাফল:

line A
line B
     1  line Z
     2  line Y
     3  line X
line C
line D

বা ওয়ার্ডকাউন্ট echo -E "${acc:1}" | wc:

line A
line B
      3       6      21
line C
line D

2

সম্পাদনা করুন ব্যবহারকারী-প্রদান করা ফিল্টার সংজ্ঞায়িত করার জন্য একটি বিকল্প যোগ

#!/usr/bin/perl -s
use IPC::Open2;
our $p;
$p = "nl" unless $p;    ## default filter

$/ = "\@\@inline-code-end\n";
while(<>) { 
   chomp;
   s/\@\@inline-code-start\n(.*)/pipeit($1,$p)/se;
   print;
}

sub pipeit{my($text,$pipe)=@_;
  open2(my $R, my $W,$pipe) || die("can open2");
  local $/ = undef;
  print $W $text;
  close $W;
  return <$R>;
}

ডিফল্ট ফিল্টারটি হল "এনএল"। কিছু ব্যবহারকারী সরবরাহিত কমান্ডের সাহায্যে ফিল্টার ব্যবহার বিকল্প "-p" পরিবর্তন করতে:

codify -p="wc" file

অথবা

codify -p="sed -e 's@^@ ║ @; 1s@^@ ╓─\n@; \$s@\$@\n ╙─@'" file

এই শেষ ফিল্টার আউটপুট হবে:

line A
line B
 ╓─
  line X
  line Y
  line Z
 ╙─
line C
line D

আপডেট 1 আইপিসির ব্যবহার :: ওপেন 2 এর স্কেলিংয়ের সমস্যা রয়েছে: যদি বাফারসাইজ অতিক্রম করে তবে এটি ব্লক হতে পারে। (আমার মেশিনে পাইপ বাফার্জেস করে যদি 64 কে 10_000 x "লাইন ওয়াই" এর সাথে মিল থাকে)।

আমাদের যদি আরও বড় জিনিস প্রয়োজন হয় (আমাদের কি 10000 "লাইনের ওয়াই" আরও প্রয়োজন):

(1) ইনস্টল এবং ব্যবহার use Forks::Super 'open2';

(২) বা এর দ্বারা ফাংশন পাইপিটের বিকল্প দিন:

sub pipeit{my($text,$pipe)=@_;
  open(F,">","/tmp/_$$");
  print F $text;
  close F;
  my $out = `$pipe < /tmp/_$$ `;
  unlink "/tmp/_$$";
  return $out;
}

ওটা সত্যিই ভালো. আমার অনুমান যে কৌশলগুলি হ'ল আপনি লাইন দ্বারা পুনরায় প্রক্রিয়াকরণ করছেন না (পুনর্নির্বাচিত $/এবং sপতাকা দ্বারা), এবং eবহিরাগত কমান্ডের প্রকৃত কলটি করার জন্য পতাকা ব্যবহার করছেন । আমি সত্যিই দ্বিতীয় (আসকি শিল্প) উদাহরণ পছন্দ করি!
জেমস স্ক্রিভেন

যদিও আমি লক্ষ্য করেছি, এটি হ'ল এটি অনুচ্ছেদে কয়েক হাজার লাইন ছাড়িয়ে গেছে। আমি অনুভব করি যে এটি সাবসেকশনটিকে পাঠ্যের একটি বড় ব্লক হিসাবে বিবেচনা করার সাথে সম্পর্কযুক্ত।
জেমস স্ক্রিভেন

ধন্যবাদ। হ্যাঁ: `/ e` = eval; /s= ("।" অর্থ (.|\n)); $/রেজিস্টার বিভাজক পুনরায় সংজ্ঞা।
জাজাও

@ জেমসস্প্রেইন, আপনি ঠিক বলেছেন (পাইপটি ব্লক করছে)। আমি যা চলছে তা পরীক্ষা করে দেখি ...
জাজাও

@ জেমসক্রিভেন, দয়া করে আমার আপডেটটি দেখুন ...
জেওয়াও

1

এটি অবাস্তব একটি কাজ।

#!/usr/bin/awk -f
$0 == "@@inline-code-start" {pipe = 1; next}
$0 == "@@inline-code-end" {pipe = 0; close("nl"); next}
pipe {print | "nl"}
!pipe {print}

স্ক্রিপ্টটি যখন শুরুর দিকে চিহ্নিত করে, এটিতে উল্লেখ করা হয় যে এটিতে পাইপিং শুরু করা উচিত nl। যখন pipeভেরিয়েবলটি সত্য হয় (ননজারো), আউটপুটটি nlকমান্ডে পাইপ করা হয় ; যখন ভেরিয়েবলটি মিথ্যা (আনসেট বা শূন্য) হয়, তখন আউটপুট সরাসরি মুদ্রিত হয়। পাইপযুক্ত কমান্ডটি প্রতিটি কমান্ড স্ট্রিংয়ের জন্য প্রথমবার পাইপ নির্মাণের মুখোমুখি হয়। একই স্ট্রিং সহ পাইপ অপারেটরের পরবর্তী মূল্যায়নগুলি বিদ্যমান পাইপটিকে পুনরায় ব্যবহার করুন; একটি ভিন্ন স্ট্রিং মান একটি পৃথক পাইপ তৈরি করবে। closeফাংশন দেওয়া কমান্ড স্ট্রিং এর জন্য পাইপ বন্ধ করে।


এটি আপনার শেল স্ক্রিপ্টের মতো নামযুক্ত পাইপ ব্যবহার করে মূলত একই যুক্তিযুক্ত, তবে বানান করা অনেক সহজ এবং ঘনিষ্ঠ যুক্তিটি সঠিকভাবে সম্পন্ন করা হয়েছে। nlকমান্ডটির বাফারগুলি ফ্লাশ করে কমান্ডটি প্রস্থান করার জন্য আপনাকে সঠিক সময়ে পাইপটি বন্ধ করতে হবে । আপনার স্ক্রিপ্টটি আসলে পাইপটি খুব তাড়াতাড়ি বন্ধ করে দেয়: পাইপটি প্রথম echo $line >myfifoসম্পাদন শেষ হওয়ার সাথে সাথেই বন্ধ হয়ে যায় । তবে nlকমান্ডটি কেবলমাত্র ফাইলটির শেষ দেখতে পাবে যদি পরবর্তী সময়ে স্ক্রিপ্টটি কার্যকর করার আগে সময় স্লাইস হয়ে যায় echo $line >myfifo। যদি আপনার কাছে প্রচুর পরিমাণে ডেটা থাকে বা আপনি sleep 1লেখার পরে যোগ করেন তবে আপনি myfifoদেখতে পাবেন যে nlকেবল প্রথম লাইনটি বা প্রথম তাত্ক্ষণিক রেখাগুলি প্রক্রিয়া করে, তবে এটি প্রস্থান করে কারণ এটি এর ইনপুটটির শেষ দেখা গেছে।

আপনার কাঠামোটি ব্যবহার করে, আপনার পাইপটির আর প্রয়োজন না হওয়া পর্যন্ত আপনাকে খোলা রাখতে হবে। পাইপে আপনার একক আউটপুট পুনর্নির্দেশ করা দরকার।

nl <myfifo &
exec 3>&1
while IFS= read -r line
do
  if [[ $line == @@inline-code-start* ]]
  then
    exec >myfifo
  elif [[ $line == @@inline-code-end* ]]
  then
    exec >&3
  else
    printf '%s\n' "$line"
  fi
done

(আমি সঠিক উদ্ধৃতি এবং এগুলি যুক্ত করার সুযোগটিও নিয়েছি - দেখুন কেন আমার শেল স্ক্রিপ্টটি সাদা স্থান বা অন্যান্য বিশেষ চরিত্রগুলিতে চেপে যায়? )

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

while IFS= read -r line
do
  if [[ $line == @@inline-code-start* ]]
  then
    while IFS= read -r line && [[ $line != @@inline-code-end* ]] do
      printf '%s\n' "$line"
    done | nl
  else
    printf '%s\n' "$line"
  fi
done

আপনার অজানা সমাধান সত্যিই দুর্দান্ত! আমি মনে করি এটি এখন পর্যন্ত সবচেয়ে সংক্ষিপ্ত (এখনও খুব পাঠযোগ্য) সমাধান। পাইপটিকে এনএল ব্যবহারের পুনরায় ব্যবহারের কী কী অভ্যাসের গ্যারান্টি দেওয়া হয়েছে, বা সিদ্ধান্ত নিতে পারে, "আরে, আপনি এখনই যথেষ্ট পাইপ দিয়েছেন..আমি এই পাইপটি বন্ধ করে নতুন একটি খুলব"? আপনার "পাইপলাইন" সমাধানটি সত্যিই দুর্দান্ত। লুপগুলির সময় আমি এমবেডেড সহ অ্যাসোনিয়ালি ডিসকাউন্ট করেছি, কারণ আমি ভেবেছিলাম এটি কিছুটা বিভ্রান্তিকর হতে পারে তবে আমি মনে করি আপনার কাছে যা আছে তা দুর্দান্ত। এর আগে একটি সেমিকোলন অনুপস্থিত do। (একটি ছোট সম্পাদনা করার জন্য আমার কাছে এখানে কোনও প্রতিনিধি নেই))
জেমস স্ক্রিভেন

1
... আমি আপনার নামযুক্ত পাইপ সমাধানটি কাজ করতে পারি না। রেসের শর্ত রয়েছে বলে মনে হয়, যেমন এনএল-তে পাইপ করা বিভাগটি কখনও কখনও পুরোপুরি হারিয়ে যায়। এছাড়াও, এফএফ-তে একটি দ্বিতীয় @@ ইনলাইন-কোড-শুরু / শেষ বিভাগ রয়েছে, এটি সর্বদা হারিয়ে যায়।
জেমস স্ক্রিভেন

0

ঠিক আছে, প্রথম বন্ধ; আমি বুঝতে পেরেছি যে আপনি নিজের ফাইলের বিভাগগুলিতে লাইনগুলি সংখ্যার উপায় খুঁজছেন না। যেহেতু আপনি আপনার ফিল্টারটি (ব্যতীত nl) কী হতে পারে তার প্রকৃত উদাহরণ দেয় নি , তাই ধরা যাক এটি

tr "[[:lower:]]" "[[:upper:]]"

অর্থাত্, পাঠ্যকে সমস্ত আপার ক্ষেত্রে রূপান্তর করুন; সুতরাং, একটি ইনপুট জন্য

line A
line B
@@inline-code-start
line X
line Y
line Z
@@inline-code-end
line C
line D

আপনি একটি আউটপুট চান

line A
line B
LINE X
LINE Y
LINE Z
line C
line D

এখানে আমার সমাধানটির প্রথম অনুমানকরণ:

#!/bin/sh
> file0
> file1
active=0
nl -ba "$@" | while IFS= read -r line
do
        case "$line" in
            ([\ 0-9][\ 0-9][\ 0-9][\ 0-9][\ 0-9][\ 0-9]"        @@inline-code-start")
                active=1
                ;;
            ([\ 0-9][\ 0-9][\ 0-9][\ 0-9][\ 0-9][\ 0-9]"        @@inline-code-end")
                active=0
                ;;
            (*)
                printf "%s\n" "$line" >> file$active
        esac
done
(cat file0; tr "[[:lower:]]" "[[:upper:]]" < file1) | sort | sed 's/^[ 0-9]\{6\}        //'

@@স্ট্রিংয়ের আগে এবং শেষ লাইনের শেষের কাছাকাছি থাকা স্থানগুলি ট্যাবগুলি। দয়া করে মনে রাখবেন যে আমি নিজের উদ্দেশ্যে ব্যবহার করছিnl । (অবশ্যই আমি সমাধান করতে এটা করছি আপনার সমস্যার , তবে আপনাকে লাইন-সংখ্যাযুক্ত আউটপুট দেওয়ার জন্য নয়))

এটি ইনপুটটির লাইনগুলিকে সংখ্যায়িত করে যাতে আমরা বিভাগের চিহ্নিতকারীদের এটিকে পৃথক করে তুলতে পারি এবং কীভাবে এটি পরে আবার একসাথে রাখা যায় তা জানতে পারি। লুপটির মূল অংশটি আপনার প্রথম প্রয়াসের উপর ভিত্তি করে বিভাগ বিভাগের মার্কারগুলিতে লাইন নম্বর রয়েছে এই বিষয়টি বিবেচনা করে নেওয়া হয়। এটি ইনপুটটিকে দুটি ফাইলে বিভক্ত করে: file0(নিষ্ক্রিয়; কোনও বিভাগে নয়) এবং file1(সক্রিয়; ইন) একটি অধ্যায়)। উপরের ইনপুটটির জন্য এগুলি দেখতে তাদের মতো:

file0:
     1  line A
     2  line B
     8  line C
     9  line D

file1:
     4  line X
     5  line Y
     6  line Z

তারপরে আমরা দৌড়ে যাই file1 ছুটে (যা সকলের সমাহার is মূলধন ফিল্টারের মাধ্যমে বিভাগের লাইনগুলির সংক্ষিপ্তকরণ); খণ্ড খণ্ড-বিভক্ত লাইনের সাথে এটি একত্রিত করুন; বাছাই করুন, তাদেরকে তাদের মূল ক্রমে ফিরিয়ে আনতে; এবং তারপরে লাইন নম্বরগুলি কেটে ফেলুন। এটি আমার উত্তরের শীর্ষের নিকটে প্রদর্শিত আউটপুট উত্পাদন করে।

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


nlইতিমধ্যে সেখানে বেশিরভাগ কাজ করে - -dএটিই এর এলিমিটার বিকল্পটি।
মাইকজার্ভ

0

একটি শেল স্ক্রিপ্ট যা অ-সীমানাবিহীন রেখাগুলির আউটপুট অংশগুলিকে শেড ব্যবহার করে এবং একটি ফিল্টার প্রোগ্রামে লাইনগুলির সীমানাযুক্ত খণ্ডগুলি সরবরাহ করে:

#!/bin/bash

usage(){
    echo "  usage: $0 <input file>"
}

# Check input file
if [ ! -f "$1" ]; then
    usage
    exit 1
fi

# Program to use for filtering
# e.g. FILTER='tr X -'
FILTER='./filter.sh'

# Generate arrays with starting/ending line numbers of demarcators
startposs=($(grep -n '^@@inline-code-start$' "$1" | cut -d: -f1))
endposs=($(grep -n '^@@inline-code-end$' "$1" | cut -d: -f1))

nums=${#startposs[*]}
nume=${#endposs[*]}

# Verify both line number arrays have the same number of elements
if (($nums != $nume)); then
    echo "Tag mismatch"
    exit 2
fi

lastline=1
i=0
while ((i < nums)); do
    # Exclude lines with code demarcators
    sprev=$((${startposs[$i]} - 1))
    snext=$((${startposs[$i]} + 1))
    eprev=$((${endposs[$i]} - 1))

    # Don't run this bit if the first demarcator is on the first line
    if ((sprev > 1)); then
        # Output lines leading up to start demarcator
        sed -n "${lastline},${sprev} p" "$1"
    fi

    # Filter lines between demarcators
    sed -n "${snext},${eprev} p" "$1" | $FILTER

    lastline=$((${endposs[$i]} + 1))
    let i++
done

# Output lines (if any) following last demarcator
sed -n "${lastline},$ p" "$1"

আমি একটি ফাইল নামে detagger.sh মধ্যে এই স্ক্রিপ্টের লিখেছিলেন এবং এটি হিসাবে তাই ব্যবহৃত: ./detagger.sh infile.txt। আমি ফিল্টারিং কার্যকারিতা নকল করতে একটি পৃথক ফিল্টার.শ ফাইল তৈরি করেছি:

#!/bin/bash
awk '{ print "\t" NR " " $0}'

ফিল্টারিং অপারেশন কোড পরিবর্তন করা যেতে পারে।

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


-1

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

আমার সমাধান:

(আমি nlকেবল উদাহরণ ফিল্টার হিসাবে ব্যবহার করি )

#!/usr/bin/bash

while read line
do
  if [[ $line == @@inline-code-start* ]]
  then
    active=true
    tmpfile=$(mktemp)
    trap "rm -f $tmpfile" EXIT
  elif [[ $line == @@inline-code-end* ]]
  then
    active=false
    <$tmpfile nl
    rm $tmpfile
  elif [[ $active = true ]]
  then
    echo $line >> $tmpfile
  else
    echo $line
  fi
done

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


আমি, ভেবেছিলাম তুমি "লাইন জুড়ে জমা রাষ্ট্র" পাবে চেয়েছিলেন, সুতরাং উদাহরণস্বরূপ মাইক টেস্ট ডেটা, লাইন ব্যবহার M, Nএবং Oসংখ্যাযুক্ত হবে 4, 5এবং 6। এটি এটি করে না। আমার উত্তরটি দেয় (বর্তমান অবতারে, এটি কোনও nlফিল্টার হিসাবে কাজ করে না ) aside যদি এই উত্তরটি আপনাকে যে আউটপুটটি দিতে চান তা দিচ্ছে, তবে "লাইনগুলি জুড়ে রাষ্ট্র জমে থাকা" বলতে কী বোঝায়? এর অর্থ কি আপনি বোঝাতে চেয়েছেন যে আপনি কেবল প্রতিটি বিভাগের মাধ্যমে রাষ্ট্র সংরক্ষণ করতে চেয়েছিলেন , কিন্তু (পার্শ্ববর্তী) বিভাগের মধ্যে নয় ? (আপনি কেন আপনার প্রশ্নের মধ্যে একটি বহু বিভাগের উদাহরণ রাখেন নি?)
স্কট

@ স্কট - nl -pপেতে ব্যবহার করুন M,N,O==4,5,6
মাইকজার্ভ

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