বাশ স্ট্রিং দিয়ে শুরু লাইনগুলি সন্ধান করে


10

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

উদাহরণস্বরূপ নিম্নলিখিত ফাইলের জন্য:

Aaaaaaaaaaaa
Baaaaaaaaaaa
Cxxxxxxxxx
Cyyyyyyyyy
Czzzzzzzzz
Abbbbbbbbbbb
Bbbbbbbbbbbb
Caaaaaa
Accccccccccc
Bccccccccccc
Cdddddd
Ceeeeee

'সি' দিয়ে শুরু করে একের বেশি লাইন রয়েছে, সুতরাং আমি চাইছি কমান্ড দ্বারা এই ফাইলটি পাওয়া যায়।
উদাহরণস্বরূপ নিম্নলিখিত ফাইলের জন্য:

Aaaaaaaaaaaa
Baaaaaaaaaaa
Cxxxxxxxxx
Abbbbbbbbbbb
Bbbbbbbbbbbb
Caaaaaa
Accccccccccc
Bccccccccccc
Cdddddd

'সি' দিয়ে সর্বদা একটি লাইন শুরু হয়, আমি এই ফাইলটি চাই না। আমি একটি grepবা একটি ব্যবহার করার কথা ভেবেছিলাম sedতবে কীভাবে এটি করা যায় তা আমি ঠিক জানি না। হতে পারে একটি রেজিপ এক্স ^C.*$^Cবা এর মতো কিছু ব্যবহার করা using কোন ধারণা ?


Cআপনার দ্বিতীয় উদাহরণ দিয়ে দুটি লাইন শুরু হচ্ছে ।
cuonglm

5
এই প্রশ্নটি অস্পষ্ট। আপনি কি এমন ফাইলগুলি সন্ধান করছেন যাগুলির সাথে এক টানা একাধিক লাইন শুরু হচ্ছে C?
গ্রামীণ

হ্যাঁ এটাই আমি চাই। ভুল জন্য দুঃখিত.
জের্মি

2
@ ইটারডন, দেখে মনে হচ্ছে যে বহু-লাইন অনুসন্ধানগুলি পি-র সাথে 2.5.4 অবধি কাজ করেছে এবং এর পরে আর হয় না, যদিও আমি চেঞ্জলগে এমন কিছু খুঁজে পাচ্ছি না যা ব্যাখ্যা করবে।
স্টাফেন চেজেলাস

1
@ গ্র্যাম আপনি নিজের উত্তরটি মুছে ফেলতে চাইতে পারেন, স্টিফেনের মন্তব্য দেখুন, সম্ভবত এটি কিছু পুরানো grepসংস্করণে কাজ করে ।
টেরডন

উত্তর:


5

সহ pcregrep:

pcregrep -rMl '^C.*\nC' .

POSIXly:

find . -type f -exec awk '
  FNR==1 {last=0; printed=0; next}
  printed {next}
  /^C/ {if (last) {print FILENAME; printed=1; nextfile} else last=1; next}
  {last=0}' {} +

(যদিও এর অর্থ সেই ফাইলগুলি awkসমর্থন করে না যা বাস্তবায়ন করে না পুরো ফাইলগুলি সম্পূর্ণরূপে পড়া nextfile)।


GNU এর সংস্করণগুলি 2.5.4 grepঅবধি রয়েছে:

grep -rlP '^C.*\nC' .

কাজ করে বলে মনে হচ্ছে তবে এটি দুর্ঘটনাবশত এবং এটির কাজের নিশ্চয়তা নেই।

এটি ২.6-এ স্থির করার আগে ( এই প্রতিশ্রুতি দিয়ে ) GNU grepউপেক্ষা করেছে যে এটি ব্যবহৃত পিসি সন্ধান ফাংশনটি বর্তমানে প্রসেস করা পুরো বাফারের সাথে মিলবে grep, এতে সমস্ত ধরণের আশ্চর্যজনক আচরণ ঘটায়। এই ক্ষেত্রে:

grep -P 'a\s*b'

সমন্বিত একটি ফাইলের সাথে মিলবে:

bla
bla

এটি মিলবে:

printf '1\n2\n' | grep -P '1\n2'

কিন্তু এই:

(printf '1\n'; sleep 1; printf '2\n') | grep -P '1\n2'

বা:

(yes | head -c 32766; printf '1\n2\n') > file; grep -P '1\n2' file

না (যেমন 1\n2\nপ্রক্রিয়াজাত করা দুটি বাফার জুড়ে রয়েছে grep)।

এই আচরণটি নথিভুক্ত হওয়া পর্যন্ত শেষ হয়েছে:

15- আমি কীভাবে লাইন জুড়ে মেলাতে পারি?

স্ট্যান্ডার্ড গ্রেপ এটি করতে পারে না, কারণ এটি মৌলিকভাবে লাইন-ভিত্তিক। সুতরাং, কেবলমাত্র '[: স্পেস:]' অক্ষর শ্রেণিটি ব্যবহার করা আপনার প্রত্যাশার সাথে নতুন লাইনের সাথে মেলে না। তবে, যদি আপনার গ্রেপ পার্ল নিদর্শনগুলি সক্ষম করে সংকলিত হয় তবে পার্লের 'মোডিফায়ার (যা'। 'এর সাথে মেলে নতুন লাইনগুলি) ব্যবহার করা যেতে পারে:

     printf 'foo\nbar\n' | grep -P '(?s)foo.*?bar'

এটি ২.6-এ স্থির হওয়ার পরে, ডকুমেন্টেশনটি সংশোধন করা হয়নি (আমি সেখানে এটি একবার জানিয়েছি )।


সেখানে কোন কারণে ব্যবহার করতে নয় exitএবং -exec \;nextfile পরিবর্তে?
টেরডন

@terdon, এর অর্থ awkপ্রতি ফাইলের জন্য একটি চালানো । আপনি কেবল তখনই এটি করতে চান যদি আপনার awkসমর্থন না করে nextfileএবং আপনার কাছে ফাইলের শুরুতে সামঞ্জস্যপূর্ণ লাইন রয়েছে এমন ফাইলগুলির একটি বৃহত পরিমাণ রয়েছে।
স্টাফেন চেজেলাস

এই গ্রেপ কৌশলটি সম্পর্কে (আমি জিএনইউ গ্রেপের আরও সাম্প্রতিক সংস্করণগুলির সাথে অনুমান করি) যা বহু ফাইলকে ম্যাচগুলিতে NUL এ লাইন টার্মিনেটর সেট করে একক স্ট্রিংয়ের মতো দেখায় - এতে যদি কোনও সীমাবদ্ধতা থাকে তবে আপনি কি সচেতন হবেন?
ইরুভার

1
@ 1_সিআর, এতে যদি কোনও নুল অক্ষর না থাকে এবং এটি ধরে নেয় যে লাইনে NUL টি অক্ষর নেই তবে পুরো ফাইলটি মেমরিতে লোড করবে। এছাড়াও মনে রাখবেন গনুহ, grep (ওপি রয়েছে) এর পুরোনো সংস্করণগুলি ব্যবহার করতে পারবেন না -zসঙ্গে -P\Nছাড়া কিছুই নেই -P, আপনাকে এটি লিখতে হবে $'[\01-\011\013-\0377]'যা কেবল সি লোকেলগুলিতে কাজ করবে ( থ্রেড.gmane.org/gmane.comp.gnu.grep.bugs/5187 দেখুন )
স্টাফেন

@ স্টাফেন চ্যাজেলাস, খুব দরকারী বিশদ, ধন্যবাদ
ইরুবার ২:18

2

সহ awk:

awk '{if (p ~ /^C/ && $1 ~ /^C/) print; p=$1}' afile.txt

এটির সাথে যদি ধারাবাহিক লাইনগুলি শুরু হয় তবে এটি ফাইলের বিষয়বস্তু মুদ্রণ করবে C। অভিব্যক্তিটি (p ~ /^C/ && $1 ~ /^C/)ফাইলে ধারাবাহিক রেখাগুলি খতিয়ে দেখবে এবং উভয় ম্যাচের প্রথম চরিত্রের ক্ষেত্রে যদি সত্য হয় তবে তা মূল্যায়ন করবে C। যদি এটি হয় তবে লাইনটি মুদ্রণ করা হবে।

এই ধরণের প্যাটার্নযুক্ত সমস্ত ফাইল সন্ধান করার জন্য, আপনি একটি findকমান্ডের মাধ্যমে উপরের অ্যাজকে চালাতে পারেন :

find /your/path -type f -exec awk '{if (p ~ /^C/ && $1 ~ /^C/) {print FILENAME; exit;} p=$1}' {} \;

এই কমান্ডে, find+ execপ্রতিটি ফাইলের মধ্য দিয়ে যাবে এবং awkপ্রতিটি ফাইলে একই রকম ফিল্টারিং সম্পাদন করবে এবং FILENAMEঅ্যাডক এক্সপ্রেশনটি যদি সত্য হিসাবে মূল্যায়ন করা হয় তবে তার নামটি প্রিন্ট করবে। FILENAMEএকাধিক ম্যাচের একক ফাইলের জন্য একাধিকবার মুদ্রণ এড়াতে exitস্টেটমেন্টটি ব্যবহৃত হয় (ধন্যবাদ @ টেরডন))


আমার প্রশ্নটি যথেষ্ট পরিষ্কার ছিল না, আমি একটানা একাধিক লাইনের সাথে ফাইলগুলির নাম জানতে চাইC
জের্মি

@ জুরমি আমি আমার উত্তর আপডেট করেছি।
এমকেসি

আপনি কীভাবে এটি কাজ করে তার একটি ব্যাখ্যা যোগ করতে পারেন? এছাড়াও, flagকেবল exitপরিবর্তে প্রয়োজন নেই । এইভাবে, কোনও ম্যাচ সন্ধানের পরে আপনার ফাইলগুলি প্রক্রিয়া করার দরকার নেই।
টেরডন

2

জিএনইউর সাথে অন্য একটি বিকল্প sed:

একটি একক ফাইলের জন্য:

sed -n -- '/^C/{n;/^C/q 1}' "$file" || printf '%s\n' "$file"

(যদিও এটি ফাইলগুলি এটি পড়তে পারে না তার প্রতিবেদন করবে)।

এর জন্য find:

find . -type f ! -exec sed -n '/^C/{n;/^C/q 1}' {} \; -print

অপঠনযোগ্য ফাইল মুদ্রিত হওয়ার সমস্যা এটিকে লিখে এড়ানো যেতে পারে:

find . -type f -size +2c -exec sed -n '$q1;/^C/{n;/^C/q}' {} \; -print

আপনি দয়া করে বিস্তারিত বলতে পারেন sed -n '$q1;/^C/{n;/^C/q}'?
Jurrmmie

আমাকে বোঝাতে কেউ?
Jérémie

@ জুরিমি $q1- প্যাটার্নটি খুঁজে পাওয়া না গেলে একটি ত্রুটি দিয়ে ছাড়তে বাধ্য করে। ফাইলের সাথে কিছু ভুল হলে এটি ত্রুটি দিয়েও শেষ হবে (এটি অপঠনযোগ্য বা ভাঙ্গা)। সুতরাং প্যাটার্নটি পাওয়া গেলে এটি 0 প্রস্থান স্থিতি দিয়ে প্রস্থান করবে এবং এটি মুদ্রণের জন্য পাস হবে। অংশ /^C/{n;/^C/qখুব সহজ। এটি সি দিয়ে শুরু হওয়া স্ট্রিংটি খুঁজে পেলে এটি পরবর্তী লাইনটি পড়বে এবং এটি সি দিয়ে শুরু হলে এটি শূন্য প্রস্থান স্থিতি সহ প্রস্থান করবে।
রাশ

1

ধরে নিচ্ছি আপনার ফাইলগুলি মেমোরিতে পড়ার মতো যথেষ্ট ছোট:

perl -000ne 'print "$ARGV\n" if /^C[^\n]*\nC/sm' *

ব্যাখ্যা:

  • - 000: \n\nরেকর্ড বিভাজক হিসাবে সেট , এটি অনুচ্ছেদে মোড চালু করে যা অনুচ্ছেদে (পরপর নতুন লাইনের দ্বারা পৃথক) একক লাইন হিসাবে বিবেচনা করবে।
  • -ne: -eইনপুট ফাইল (গুলি) এর প্রতিটি লাইনে যুক্তি হিসাবে দেওয়া স্ক্রিপ্টটি প্রয়োগ করুন apply
  • $ARGV : ফাইলটি বর্তমানে প্রক্রিয়াজাত হচ্ছে
  • /^C[^\n]*\nC/: Cএকটি লাইনের শুরুর দিকে ম্যাচ করুন ( smকেন এটি এখানে কাজ করে তার জন্য নীচের সংশোধনকারীদের বিবরণ দেখুন ) এর পরে 0 বা আরও নন-লাইন অক্ষর, একটি নতুন লাইন এবং তারপরে অন্য সি। অন্য কথায়, একটানা লাইনগুলি শুরু করে সন্ধান করুন C। * //sm: এই ম্যাচ সংশোধকগুলি হ'ল (এখানে দলিল হিসাবে [এখানে]):

    • মি : একাধিক লাইন হিসাবে স্ট্রিং আচরণ। এটি হ'ল স্ট্রিংয়ের বাম এবং ডান প্রান্তে কেবল স্ট্রিংয়ের বাম এবং ডান প্রান্তে লাইনটির শুরু বা শেষের সাথে মিলে যাওয়া থেকে "^" এবং "$" পরিবর্তন করুন them

    • s : স্ট্রিংটিকে একক লাইন হিসাবে বিবেচনা করুন। অর্থাৎ, পরিবর্তন ""। যে কোনও চরিত্রের সাথে মিল রাখতে, এমনকি একটি নতুন লাইনও, যা সাধারণত এটি মেলে না।

আপনি কুরুচিপূর্ণ কিছু করতেও পারেন:

for f in *; do perl -pe 's/\n/%%/' "$f" | grep -q 'C[^%]*%%C' && echo "$f"; done

এখানে, perlকোড সহ নতুন লাইন প্রতিস্থাপন %%তাই হয়, অভিমানী আপনি কোন আছে %%আপনার ইনপুট ফাইলে (বড় যদি অবশ্যই), grepদিয়ে শুরু পরপর লাইন ম্যাচ হবে C


1

সমাধান:

( set -- *files ; for f ; do (
set -- $(printf %c\  `cat <$f`)
while [ $# -ge 1 ] ;do [ -z "${1#"$2"}" ] && {
    echo "$f"; break ; } || shift
done ) ; done )

ডেমো:

প্রথমত, আমরা একটি পরীক্ষার বেস তৈরি করব:

abc="a b c d e f g h i j k l m n o p q r s t u v w x y z" 
for l in $abc ; do { i=$((i+1)) h= c= ;
    [ $((i%3)) -eq 0 ] && c="$l" h="${abc%"$l"*}"
    line="$(printf '%s ' $h $c ${abc#"$h"})"
    printf "%s$(printf %s $line)\n" $line >|/tmp/file${i}
} ; done

উপরোক্ত /tmpনামে 26 টি ফাইল তৈরি করে file1-26প্রতিটি ফাইলে 27 বা 28 টি লাইন অক্ষর দিয়ে শুরু হয় a-zএবং তারপরে বাকী বর্ণমালা থাকে। প্রতি তৃতীয় ফাইলটিতে পরপর দুটি লাইন থাকে যার মধ্যে প্রথম অক্ষরটি নকল হয়।

নমুনা:

cat /tmp/file12
...
aabcdefghijkllmnopqrstuvwxyz
babcdefghijkllmnopqrstuvwxyz
cabcdefghijkllmnopqrstuvwxyz
...
kabcdefghijkllmnopqrstuvwxyz
labcdefghijkllmnopqrstuvwxyz
labcdefghijkllmnopqrstuvwxyz
mabcdefghijkllmnopqrstuvwxyz
...

এবং যখন আমি পরিবর্তন করি:

set -- *files

প্রতি:

set -- /tmp/file[0-9]*

আমি পাই...

আউটপুট:

/tmp/file12
/tmp/file15
/tmp/file18
/tmp/file21
/tmp/file24
/tmp/file3
/tmp/file6
/tmp/file9

সুতরাং, সংক্ষেপে, সমাধানটি এর মতো কাজ করে:

setগুলি subshell আপনার ফাইল সব positionals, এবং প্রতিটি জন্য

setপ্রতিটি ফাইলের প্রতিটি পংক্তির প্রথম অক্ষরটি যেমন লুপ হয়ে যায় তেমনি একটি নেস্টেড সাবশেলের অবস্থানগুলি s

[ tests ]যদি কোনও ম্যাচ নির্দেশ করে এবং যদি তা $1উপেক্ষা $2করে

echoesফাইলের নাম তারপর breakগুলি বর্তমান লুপ পুনরাবৃত্তির

অন্য shiftগুলি পরবর্তী একক অক্ষর অবস্থানগত পুনরায় চেষ্টা করতে


0

এই স্ক্রিপ্টটি ম্যাচের লাইনের লাইন নম্বরগুলি ব্যবহার করে grepএবং cutযে কোনও দুটি টানা সংখ্যার জন্য পরীক্ষা করে। স্ক্রিপ্টের প্রথম আর্গুমেন্ট হিসাবে ফাইলটি একটি বৈধ ফাইলের নামটি পাস বলে ধরে নেওয়া হয়েছে:

#!/bin/bash

checkfile () {
 echo checking $1
 grep -n -E "^C.*$" $1 | cut -d: -f1 | while read linenum
     do
        : $[ ++PRV ] 
        if [ $linenum == $PRV ]; then return 1; fi
        PRV=$linenum
     done
     return 0
}

PRV="-1"
checkfile $1
if [ $? == 0 ]; then
   echo Consecutive matching lines found in file $1
fi
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.