Grep ප්‍රතිදානයට ගැලපෙන නිශ්චිත කණ්ඩායම් පමණක් කළ හැකිද?


343

මට ගොනුවක් ඇති බව පවසන්න:

# file: 'test.txt'
foobar bash 1
bash
foobar happy
foobar

මට දැන ගැනීමට අවශ්‍ය වන්නේ "ෆූබාර්" ට පසුව දිස්වන වචන මොනවාද, එබැවින් මට මෙම රීජෙක්ස් භාවිතා කළ හැකිය:

"foobar \(\w\+\)"

වරහන් මගින් පෙන්නුම් කරන්නේ ෆූබාර්ට පසුව මට වචනය කෙරෙහි විශේෂ උනන්දුවක් ඇති බවයි. නමුත් මම එය කරන විට grep "foobar \(\w\+\)" test.txt, "ෆූබාර් පසු වචනය" වෙනුවට සමස්ත රීජෙක්ස් වලට ගැලපෙන සම්පූර්ණ රේඛා මට ලැබේ:

foobar bash 1
foobar happy

මම කැමතියි එම විධානයේ ප්‍රතිදානය මේ වගේ බව:

bash
happy

නිත්‍ය ප්‍රකාශනයකින් කණ්ඩායම්කරණයට (හෝ විශේෂිත කණ්ඩායම්කරණයට) ගැලපෙන අයිතම පමණක් ප්‍රතිදානය කිරීමට grep ට පැවසීමට ක්‍රමයක් තිබේද?


6
grep අවශ්‍ය නැති අය සඳහා:perl -lne 'print $1 if /foobar (\w+)/' < test.txt
vault

වරහන් වලින් ගැලවීමට ඔබට අවශ්‍ය වන්නේ +කෙසේද?
සෙබස්තියන්

එය regex දැක්වීමට කන්ඩායමක් හා ගැලපෙන 1 කට හෝ ඊට වැඩි චරිත සැබෑ චරිත සොයමින් වෙනුවට (, )හා +.
කෝරි ක්ලයින්

Answers:


378

GNU grep සතුව -Pperl-style regexes සඳහා -oවිකල්පයක් ඇති අතර රටාවට ගැලපෙන දේ පමණක් මුද්‍රණය කිරීමේ විකල්පය ඇත. ග්‍රෙප් රටාවේ කොටසක් අරමුණු සඳහා ගැලපෙන බව තීරණය කර ඇති දේවලින් ඉවත් කිරීම සඳහා බැලීමේ වටපිටාව (පර්ල්ර් මෑන්පේජ් හි විස්තාරිත රටා යටතේ විස්තර කර ඇත) භාවිතයෙන් මේවා ඒකාබද්ධ කළ හැකිය -o.

$ grep -oP 'foobar \K\w+' test.txt
bash
happy
$

මෙම \Kකෙටි-ආකෘතිය (සහ වඩාත් කාර්යක්ෂම ආකෘති පත්රය) වේ (?<=pattern), ඔබ ඔබ ප්රතිදානය කිරීමට අවශ්ය පෙළ පෙර ශුන්ය-පළල පෙනුම-පිටුපස සහතික කිරීමක් ලෙස භාවිතා කරන්න. (?=pattern)ඔබට ප්‍රතිදානය කිරීමට අවශ්‍ය පෙළට පසුව ශුන්‍ය පළල දෙස බැලීමේ ප්‍රකාශයක් ලෙස භාවිතා කළ හැකිය.

උදාහරණයක් ලෙස, fooසහ අතර ඇති වචනය ගැලපීමට ඔබට අවශ්‍ය නම් bar, ඔබට මෙය භාවිතා කළ හැකිය:

$ grep -oP 'foo \K\w+(?= bar)' test.txt

හෝ (සමමිතිය සඳහා)

$ grep -oP '(?<=foo )\w+(?= bar)' test.txt

5
ඔබේ රීජෙක්ස් සමූහකරණයට වඩා වැඩි නම් ඔබ එය කරන්නේ කෙසේද? (මාතෘකාවට අනුව?)
බැරැසල්

5
@barracel: ඔබට හැකි යැයි මම විශ්වාස නොකරමි. වේලාවsed(1)
camh

1
amcamh grep -oP 'foobar \K\w+' test.txtOP සමඟ කිසිවක් ප්‍රතිදානය නොකරන බව මම දැන් පරීක්ෂා කර ඇත්තෙමි test.txt. Grep අනුවාදය 2.5.1 වේ. වැරැද්ද කුමක් විය හැකිද? O_O
SOUser

Ic සිචෙන්ලි: මට කියන්න බැහැ. මම දැන් grep වල v2.5.1 ගොඩනගා ඇත (එය තරමක් පැරණි - 2006 සිට) එය මට වැඩ කළේය.
camh

OUSOUser: මම එයම අත්විඳිමි - ගොනු කිරීමට කිසිවක් ප්‍රතිදානය නොකරයි. මෙය මට වැඩ කරන බැවින් ප්‍රතිදානය යැවීම සඳහා ගොනු නාමයට පෙර '>' ඇතුළත් කරන ලෙස මම සංස්කරණ ඉල්ලීම ඉදිරිපත් කළෙමි.
rjchicago

50

සම්මත grep හට මෙය කළ නොහැක, නමුත් GNU grep හි මෑත සංස්කරණ වලට හැකිය . ඔබට sed, awk හෝ perl වෙත හැරිය හැකිය. ඔබේ නියැදි ආදානයෙන් ඔබට අවශ්‍ය දේ කරන උදාහරණ කිහිපයක් මෙන්න; ඔවුන් කෙළවරේ අවස්ථා වලදී තරමක් වෙනස් ලෙස හැසිරේ.

වෙනුවට foobar word other stuffවිසින් word, ඒ වෙනුවට වෙනත් සිදු වුවහොත් පමණක් මුද්රණය කරන්න.

sed -n -e 's/^foobar \([[:alnum:]]\+\).*/\1/p'

පළමු වචනය නම් foobar, දෙවන වචනය මුද්‍රණය කරන්න.

awk '$1 == "foobar" {print $2}'

තීරය foobarඑය පළමු වචනය, සහ වෙනත් ආකාරයකින් රේඛාව මඟ නම්, පළමු සුදු අවකාශයෙන් පසුව සියල්ල ඉවත් කර මුද්‍රණය කරන්න.

perl -lne 's/^foobar\s+// or next; s/\s.*//; print'

නියමයි! මම සිතුවේ මට මෙය සෙඩ් සමඟ කළ හැකි යැයි කියාය, නමුත් මම මීට පෙර එය භාවිතා කර නැති අතර මගේ හුරුපුරුදුකම භාවිතා කළ හැකියැයි බලාපොරොත්තුවෙන් සිටියෙමි grep. නමුත් මෙම විධානයන් සඳහා වන වාක්‍ය ඛණ්ඩය දැන් ඉතා හුරුපුරුදු බව පෙනේ. ස්තූතියි ටොන්.
කෝරි ක්ලයින්

1
ඇත්ත නොවේ, ගිලෙස්. GNU grep විසඳුමක් සඳහා මගේ පිළිතුර බලන්න.
camh

1
amcamh: අහ්, මම දැනගෙන හිටියේ නැහැ GNU grep ට දැන් සම්පූර්ණ PCRE සහය තියෙනවා කියලා. මම මගේ පිළිතුර නිවැරදි කළා, ස්තූතියි.
ගිලෙස්ගේ SO- නපුරු වීම නවත්වන්න '

1
grepකාර්යබහුල පෙට්ටියට PCRE සහය නොමැති බැවින් මෙම පිළිතුර කාවැද්දූ ලිනක්ස් සඳහා විශේෂයෙන් ප්‍රයෝජනවත් වේ .
ක්‍රේග් මැක්වීන්

ඉදිරිපත් කරන ලද එකම කාර්යය ඉටු කිරීම සඳහා විවිධ ක්‍රම තිබේ, කෙසේ වෙතත්, OP විසින් grep භාවිතය ඉල්ලා සිටියහොත්, ඔබ වෙනත් දෙයකට පිළිතුරු දෙන්නේ ඇයි? එසේම, ඔබගේ පළමු ඡේදය වැරදියි: ඔව් grep හට එය කළ හැකිය.
fcm

47
    sed -n "s/^.*foobar\s*\(\S*\).*$/\1/p"

-n     suppress printing
s      substitute
^.*    anything before foobar
foobar initial search match
\s*    any white space character (space)
\(     start capture group
\S*    capture any non-white space character (word)
\)     end capture group
.*$    anything after the capture group
\1     substitute everything with the 1st capture group
p      print it

2
Sed උදාහරණය සඳහා +1, grep වලට වඩා කාර්යය සඳහා වඩා හොඳ මෙවලමක් සේ පෙනේ. එක් අදහසක්, ^සහ $බාහිර ඒවා .*කෑදර තරගයකි. කෙසේ වෙතත්, ඒවා ඇතුළත් කිරීම රීජෙක්ස් හි අභිප්‍රාය පැහැදිලි කිරීමට උපකාරී වේ.
ටෝනි

මට මුලදී එකතු කිරීමට අවශ්‍ය .*විය. එසේ නොවුවහොත් එය ෆූබාර් කිරීමට පෙර තිබූ දේ ද ග්‍රහණය කර ගත්තේය.
aerijman

20

හොඳයි, foobar සෑම විටම පළමු වචනය හෝ රේඛාව බව ඔබ දන්නවා නම්, ඔබට කප්පාදුව භාවිතා කළ හැකිය. එසේ වැනි:

grep "foobar" test.file | cut -d" " -f2

මෙම -oඅයිතිය සුරකියි මත මාරු පුළුල් ලෙස එසේ කිරීම මගින්, (වුවාට යනු GNU අයිතිය සුරකියි දිගු වඩා) ක්රියාත්මක grep -o "foobar" test.file | cut -d" " -f2lookbehind කථනයන් භාවිතා වඩා එහා මෙහා ගෙන යා හැකි වන, මෙම විසඳුම වල සඵලතාවය වැඩි වනු ඇත.
dubiousjim

1
මම ඔබට අවශ්ය වනු ඇතැයි විශ්වාස grep -o "foobar .*"හෝ grep -o "foobar \w+".
G-මෑන් කියයි 'නැවත සේවයේ පිහිටුවීමට මොනිකා'

අගයේ තවත් ඉඩක් තිබේ නම්
කැඩී යයි

13

pcregrepඔබට වඩා හොඳ -oවිකල්පයක් ඇත, එය ඔබට ප්‍රතිදානය අවශ්‍ය කුමන ග්‍රහණ කණ්ඩායම් තෝරා ගැනීමට ඉඩ දෙයි. එබැවින්, ඔබේ උදාහරණ ගොනුව භාවිතා කරමින්,

$ pcregrep -o1 "foobar (\w+)" test.txt
bash
happy

ඇවැත්නි, මෙය මට ඉන්ද්‍රජාලික විය, ඔබට බොහෝම ස්තූතියි. මම මැකෝස් හි සිටිමි, කෙසේ හෝ තරඟ කණ්ඩායම් භාවිතා කිරීමට උත්සාහ කරමින් සිටියෙමි. මම උත්සාහ zegrepකළේ මා විශාල සිප් ගොනුවක් අඹරමින් සිටි නිසා පමණක් නොව, pcregrep ( pcregrep --helpපිටුවෙන්) කරන බවත් සොයා ගත් හෙයිනි : Files whose names end in .gz are read using zlib. එබැවින් මට එය මගේ zip ගොනුවේ කෙලින්ම භාවිතා කළ හැකිය. නැවත ස්තූතියි!
samjewell

9

PCRE සහය නොදක්වන්නේ නම් ඔබට grep හි ආයාචනා දෙකක් සමඟ එකම ප්‍රති result ලය ලබා ගත හැකිය. උදාහරණයක් ලෙස foobar පසු වචනය අල්ලා ගැනීමට මෙය කරන්න:

<test.txt grep -o 'foobar  *[^ ]*' | grep -o '[^ ]*$'

මේ වගේ foobar පසු අත්තනෝමතික වචනයකට මෙය පුළුල් කළ හැකිය (කියවීමේ හැකියාව සඳහා ERE සමඟ):

i=1
<test.txt egrep -o 'foobar +([^ ]+ +){'$i'}[^ ]+' | grep -o '[^ ]*$'

ප්‍රතිදානය:

1

දර්ශකය iශුන්‍ය මත පදනම් වූ බව සලකන්න .


7

භාවිතා grepකිරීම හරස් වේදිකා අනුකූල නොවේ, මන්ද -P/ --perl-regexpලබා ගත හැක්කේ ග්නූgrep මත මිස BSDgrep නොවේ .

පහත දැක්වෙන විසඳුම මෙන්න ripgrep:

$ rg -o "foobar (\w+)" -r '$1' <test.txt
bash
happy

අනුව man rg:

-r/ --replace REPLACEMENT_TEXTලබා පෙළ සෑම තරගය ආදේශ කරන්න.

ආදේශන නූලෙහි ග්‍රහණ කණ්ඩායම් දර්ශක (උදා, $5) සහ නම් (උදා. $foo) සහය දක්වයි.

ආශ්‍රිත: GH-462 .


2

මට @jgshawkey හි පිළිතුර ඉතා ප්‍රයෝජනවත් විය. grepමේ සඳහා එතරම් හොඳ මෙවලමක් නොවේ, නමුත් sed යනු, මෙහි දී අපට අදාළ රේඛාවක් උදුරා ගැනීමට grep භාවිතා කරන උදාහරණයක් ඇත.

ඔබ පුරුදු නැතිනම් sed හි Regex syntax එක මුග්ධ වේ.

මෙන්න තවත් උදාහරණයක්: හැඳුනුම් සංඛ්‍යාවක් ලබා ගැනීම සඳහා මෙය xinput හි ප්‍රතිදානය විග්‍රහ කරයි

⎜   ↳ SynPS/2 Synaptics TouchPad                id=19   [slave  pointer  (2)]

මට 19 ක් අවශ්‍යයි

export TouchPadID=$(xinput | grep 'TouchPad' | sed  -n "s/^.*id=\([[:digit:]]\+\).*$/\1/p")

පන්ති සින්ටැක්ස් සටහන:

[[:digit:]]

සහ පහත සඳහන් දේවලින් ගැලවීමේ අවශ්‍යතාවය +

මම හිතන්නේ එක් පේළියක් පමණක් ගැලපේ.


මම කරන්න උත්සාහ කළේ මෙයයි. ස්තූතියි!
ජේම්ස්

grep'ටච් පෑඩ්' යනු 'හැඳුනුම්පතේ' වම්පස යැයි උපකල්පනය කරමින්, අමතර නොමැතිව තරමක් සරල අනුවාදය :echo "SynPS/2 Synaptics TouchPad id=19 [slave pointer (2)]" | sed -nE "s/.*TouchPad.+id=([0-9]+).*/\1/p"
අමිත් නායිදු
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.