ගොනුවක (ය) නූලක් ආදේශ කරන්නේ කෙසේද?


794

ඇතැම් සෙවුම් නිර්ණායක මත පදනම්ව ලිපිගොනු වල නූල් ආදේශ කිරීම ඉතා පොදු කාර්යයකි. මට කොහොමද?

  • වත්මන් නාමාවලියෙහි ඇති සියලුම ලිපිගොනු fooසමඟ නූල් ආදේශ කරන්න bar?
  • උප නාමාවලි සඳහාද එය පුනරාවර්තනයක් කරන්නේද?
  • ගොනුවේ නම වෙනත් නූලකට ගැලපෙන්නේ නම් පමණක් ආදේශ කරන්න?
  • යම් සන්දර්භයක් තුළ නූල හමු වුවහොත් පමණක් ආදේශ කරන්න?
  • නූල නිශ්චිත රේඛා අංකයක තිබේ නම් ප්‍රතිස්ථාපනය කරන්න?
  • එකම ආදේශනයකින් බහු නූල් ආදේශ කරන්න
  • විවිධ නූල් වෙනුවට විවිධ නූල් ආදේශ කරන්න

2
මෙය මෙම විෂය පිළිබඳ කැනොනිකල් ප්‍රශ්නෝත්තරයක් වීමට අදහස් කරයි (මෙම මෙටා සාකච්ඡාව බලන්න ), කරුණාකර මගේ පිළිතුර පහත සංස්කරණය කිරීමට හෝ ඔබේම දෑ එකතු කිරීමට නිදහස් වන්න.
terdon

නියමයි grep -rl(පසුව නල මාර්ගයටsed ) පිළිතුරු දෙන්න: unix.stackexchange.com/questions/472476/…
ගේබ්‍රියෙල් ස්ටැපල්ස්

Answers:


1066

1. වත්මන් නාමාවලියෙහි ඇති සියලුම ලිපිගොනු වල එක් සිදුවීමක තවත් සිදුවීමක් වෙනත් නූලක් සමඟ ප්‍රතිස්ථාපනය කිරීම:

මේවා නාමාවලියෙහි අඩංගු වන්නේ සාමාන්‍ය ලිපිගොනු පමණක් බවත් සැඟවුණු නොවන සියලුම ගොනු සැකසීමට ඔබට අවශ්‍ය බවත් ඔබ දන්නා අවස්ථා සඳහා ය . එය එසේ නොවේ නම්, 2 හි ප්‍රවේශයන් භාවිතා කරන්න.

sedමෙම පිළිතුරේ ඇති සියලුම විසඳුම් GNU උපකල්පනය sedකරයි. FreeBSD හෝ OS / X භාවිතා කරන්නේ නම්, ආදේශ -iකරන්න -i ''. -iඕනෑම අනුවාදයක් සමඟ ස්විචය භාවිතා කිරීම sedසමහර ගොනු පද්ධති ආරක්ෂණ ඇඟවුම් ඇති අතර ඔබ ඕනෑම ආකාරයකින් බෙදා හැරීමට අදහස් කරන ඕනෑම ස්ක්‍රිප්ට් එකක එය කළ නොහැකි බව සලකන්න.

  • පුනරාවර්තන නොවන, මෙම නාමාවලියෙහි ඇති ගොනු පමණි:

    sed -i -- 's/foo/bar/g' *
    perl -i -pe 's/foo/bar/g' ./* 

    ( perlඑකක් |හෝ අවකාශයකින් අවසන් වන ගොනු නම් සඳහා එය අසමත් වනු ඇත ) ).

  • මෙහි සහ සියලුම උප බහලුම්වල පුනරාවර්තන, සාමාන්‍ය ලිපිගොනු ( සැඟවුණු ඒවා ඇතුළුව )

    find . -type f -exec sed -i 's/foo/bar/g' {} +

    ඔබ zsh භාවිතා කරන්නේ නම්:

    sed -i -- 's/foo/bar/g' **/*(D.)

    (ලැයිස්තුව ඉතා විශාල නම් අසමත් විය හැකිය, zargsවැඩ කිරීමට බලන්න ).

    සාමාන්‍ය ලිපිගොනු සඳහා බාෂ් කෙලින්ම පරීක්ෂා කළ නොහැක, ලූපයක් අවශ්‍ය වේ (වරහන් ගෝලීයව විකල්ප සැකසීමෙන් වළකින්න):

    ( shopt -s globstar dotglob;
        for file in **; do
            if [[ -f $file ]] && [[ -w $file ]]; then
                sed -i -- 's/foo/bar/g' "$file"
            fi
        done
    )

    ලිපිගොනු තෝරාගනු ලබන්නේ ඒවා සත්‍ය ලිපිගොනු (-f) වන අතර ඒවා ලිවිය හැකි (-w) වේ.

2. ගොනුවේ නම වෙනත් නූලකට ගැලපෙන්නේ නම් / නිශ්චිත දිගුවක් තිබේ නම් / යම් වර්ගයක නම් පමණක් ආදේශ කරන්න:

  • පුනරාවර්තන නොවන, මෙම නාමාවලියෙහි ඇති ගොනු පමණි:

    sed -i -- 's/foo/bar/g' *baz*    ## all files whose name contains baz
    sed -i -- 's/foo/bar/g' *.baz    ## files ending in .baz
  • මෙහි සහ සියලුම උප බහලුම්වල පුනරාවර්තන, සාමාන්‍ය ලිපිගොනු

    find . -type f -name "*baz*" -exec sed -i 's/foo/bar/g' {} +

    ඔබ bash භාවිතා කරන්නේ නම් (වරහන් ගෝලීයව විකල්ප සැකසීමෙන් වළකින්න):

    ( shopt -s globstar dotglob
        sed -i -- 's/foo/bar/g' **baz*
        sed -i -- 's/foo/bar/g' **.baz
    )

    ඔබ zsh භාවිතා කරන්නේ නම්:

    sed -i -- 's/foo/bar/g' **/*baz*(D.)
    sed -i -- 's/foo/bar/g' **/*.baz(D.)

    මෙම --කියන්න සේවය sedතවත් කොඩි විධාන රේඛාවේ ලබා දුන් බව. ආරම්භ වන ගොනු නාම වලින් ආරක්ෂා වීමට මෙය ප්‍රයෝජනවත් වේ -.

  • ගොනුවක් කිසියම් වර්ගයක නම්, උදාහරණයක් ලෙස, ක්‍රියාත්මක කළ හැකි ( man findතවත් විකල්ප සඳහා බලන්න ):

    find . -type f -executable -exec sed -i 's/foo/bar/g' {} +

    zsh:

    sed -i -- 's/foo/bar/g' **/*(D*)

3. යම් සන්දර්භයක් තුළ නූල හමු වුවහොත් පමණක් ප්‍රතිස්ථාපනය කරන්න

  • වෙනුවට fooසමග barකාලයක් පවතින්නේ නම් පමණක් bazඑම මාර්ගයේ පසුව:

    sed -i 's/foo\(.*baz\)/bar\1/' file

    දී sedභාවිතා \( \)වරහන් තුළ වන අතර, එසේ නම් ඔබ එය සමග ප්රවේශ විය හැකි ඕනෑම දෙයක් ඉතිරි \1. මෙම තේමාවේ බොහෝ වෙනස්කම් ඇත, එවැනි නිත්‍ය ප්‍රකාශන ගැන වැඩි විස්තර දැනගැනීම සඳහා මෙහි බලන්න .

  • වෙනුවට fooසමග barනම් පමණක් fooආදාන ගොනු 3d තීරුව (ක්ෂේත්ර) සදහන් කර ඇත (whitespace-වෙන් ක්ෂේත්ර උපකල්පනය කරමින්):

    gawk -i inplace '{gsub(/foo/,"baz",$3); print}' file

    ( gawk4.1.0 හෝ නව අවශ්‍ය වේ).

  • වෙනත් ක්ෂේත්‍රයක් සඳහා උනන්දුවක් දක්වන ක්ෂේත්‍රයේ අංකය $Nකොතැනද Nයන්න භාවිතා කරන්න . වෙනත් ක්ෂේත්‍ර බෙදුම්කරුවෙකු සඳහා ( :මෙම උදාහරණයේ) භාවිතා කරන්න:

    gawk -i inplace -F':' '{gsub(/foo/,"baz",$3);print}' file

    භාවිතා කරන තවත් විසඳුමක් perl:

    perl -i -ane '$F[2]=~s/foo/baz/g; $" = " "; print "@F\n"' foo 

    සටහන: awkසහ perlවිසඳුම් යන දෙකම ගොනුවේ පරතරයට බලපානු ඇත (ප්‍රමුඛ හා පසුපස හිස් ඉවත් කරන්න, සහ ගැලපෙන රේඛාවල හිස් අනුපිළිවෙල එක් අවකාශ අක්ෂරයකට පරිවර්තනය කරන්න). වෙනස් ක්ෂේත්ර සඳහා, භාවිතා $F[N-1]එහිදී Nඔබට අවශ්ය ක්ෂේත්ර අංකය සහ විවිධ ක්ෂේත්ර වෙන්කර භාවිතය සඳහා (යනු $"=":"ප්රතිදාන ක්ෂේත්රයේ වෙන්කර සකසයි :):

    perl -i -F':' -ane '$F[2]=~s/foo/baz/g; $"=":";print "@F"' foo 
  • වෙනුවට fooසමග bar4 වන රේඛාව මත පමණක්:

    sed -i '4s/foo/bar/g' file
    gawk -i inplace 'NR==4{gsub(/foo/,"baz")};1' file
    perl -i -pe 's/foo/bar/g if $.==4' file

4. බහු ආදේශන මෙහෙයුම්: විවිධ නූල් සමඟ ප්‍රතිස්ථාපනය කරන්න

  • ඔබට sedවිධාන ඒකාබද්ධ කළ හැකිය :

    sed -i 's/foo/bar/g; s/baz/zab/g; s/Alice/Joan/g' file

    සඳහා කරුණු (බව දැනුවත් විය sed 's/foo/bar/g; s/bar/baz/g'ආදේශ කරනු ඇත fooසමඟ baz).

  • හෝ පර්ල් විධාන

    perl -i -pe 's/foo/bar/g; s/baz/zab/g; s/Alice/Joan/g' file
  • ඔබට රටා විශාල සංඛ්‍යාවක් තිබේ නම්, ඔබේ රටා සහ ඒවායේ ප්‍රතිස්ථාපන sedස්ක්‍රිප්ට් ගොනුවක සුරැකීම පහසුය :

    #! /usr/bin/sed -f
    s/foo/bar/g
    s/baz/zab/g
  • නැතහොත්, ඉහත සඳහන් කළ හැකි තරම් රටා යුගල ඔබට තිබේ නම්, ඔබට ගොනුවකින් රටා යුගල කියවිය හැකිය (අවකාශය වෙන් කළ රටා දෙකක්, $ රටාව සහ $ එක් පේළියකට ආදේශ කිරීම):

    while read -r pattern replacement; do   
        sed -i "s/$pattern/$replacement/" file
    done < patterns.txt
  • දිගු රටා සහ විශාල දත්ත ගොනු සඳහා එය තරමක් මන්දගාමී වනු ඇත, එවිට ඔබට රටා කියවා sedඒ වෙනුවට ස්ක්‍රිප්ට් එකක් සෑදීමට අවශ්‍ය වනු ඇත . පහත දැක්වෙන්නේ <space> පරිසීමකය ගොනුවේ එක් පේළියකට එක් වන MATCH <space> ප්‍රතිස්ථාපන යුගල ලැයිස්තුවක් වෙන් කරයි patterns.txt:

    sed 's| *\([^ ]*\) *\([^ ]*\).*|s/\1/\2/g|' <patterns.txt |
    sed -f- ./editfile >outfile

    ඉහත ආකෘතිය උදාහරණයක් ලෙස, ඉඩ දෙන්නේ නැත විශාල වශයෙන් අත්තනෝමතික වන අතර, <හිස්තැනක්> එක්කෝ ක මැච් හෝ ආදේශ කරන්න . මෙම ක්‍රමය ඉතා සාමාන්‍ය වුවත්: මූලික වශයෙන්, ඔබට sedපිටපතක් මෙන් පෙනෙන ප්‍රතිදාන ප්‍රවාහයක් නිර්මාණය කළ හැකි නම්, ඔබට එම ප්‍රවාහය ස්ක්‍රිප්ට් ගොනුවක් ස්ටැඩින් ලෙස sedසඳහන් කිරීමෙන් ස්ක්‍රිප්ට් එකක් ලෙස ලබා ගත හැකිය .sed-

  • ඔබට සමාන ආකාරයකින් බහු ස්ක්‍රිප්ට් ඒකාබද්ධ කර සංයුක්ත කළ හැකිය:

    SOME_PIPELINE |
    sed -e'#some expression script'  \
        -f./script_file -f-          \
        -e'#more inline expressions' \
    ./actual_edit_file >./outfile

    POSIX sedමඟින් විධාන රේඛාවේ දිස්වන අනුපිළිවෙලින් සියලුම ස්ක්‍රිප්ට් එකකට සංයුක්ත කරයි. මේ කිසිවක් අවශ්‍ය \nනොවේ.

  • grep එකම ආකාරයකින් වැඩ කළ හැකිය:

    sed -e'#generate a pattern list' <in |
    grep -f- ./grepped_file
  • ස්ථාවර නූල් රටා ලෙස වැඩ කරන විට, නිත්‍ය ප්‍රකාශන මෙටාචරැක්ටර් වලින් ගැලවීම හොඳ පුරුද්දකි . ඔබට මෙය පහසුවෙන් කළ හැකිය:

    sed 's/[]$&^*\./[]/\\&/g
         s| *\([^ ]*\) *\([^ ]*\).*|s/\1/\2/g|
    ' <patterns.txt |
    sed -f- ./editfile >outfile

5. බහු ප්‍රතිස්ථාපන මෙහෙයුම්: එකම රටාවකින් රටා කිහිපයක් ආදේශ කරන්න

  • ඕනෑම වෙනුවට foo, barහෝ bazසමගfoobar

    sed -Ei 's/foo|bar|baz/foobar/g' file
  • හෝ

    perl -i -pe 's/foo|bar|baz/foobar/g' file

2
@ ස්ටෙෆාන් චැසෙලාස් සංස්කරණයට ස්තූතියි, එය ඇත්ත වශයෙන්ම කරුණු කිහිපයක් නිවැරදි කළේය. කෙසේ වෙතත්, කරුණාකර බැෂ් වලට අදාළ තොරතුරු ඉවත් නොකරන්න. සෑම කෙනෙකුම භාවිතා නොකරයි zsh. සෑම ආකාරයකින්ම zshතොරතුරු එක් කරන්න, නමුත් බාෂ් දේවල් ඉවත් කිරීමට හේතුවක් නැත. එසේම, පෙළ සැකසීම සඳහා කවචය භාවිතා කිරීම වඩාත් සුදුසු නොවන බව මම දනිමි, නමුත් එය අවශ්‍ය අවස්ථාවන් තිබේ. මගේ මුල් පිටපතෙහි වඩා හොඳ අනුවාදයකින් මම සංස්කරණය කළෙමි, එය sedවිග්‍රහ කිරීම සඳහා ෂෙල් ලූපය භාවිතා කරනවා වෙනුවට පිටපතක් සාදනු ඇත. උදාහරණයක් ලෙස ඔබට රටා යුගල සිය ගණනක් තිබේ නම් මෙය ප්‍රයෝජනවත් වේ.
ටර්ඩන්

2
ඩර්ඩන්, ඔබේ කඩාවැටීම වැරදියි. 4.3 ට පෙර බැෂ් බැසීමේදී සිම්ලින්ක් අනුගමනය කරයි. එසේම (.)බාෂ් ග්ලෝබින් සුදුසුකම් සඳහා සමාන නොවන බැවින් මෙහි භාවිතා කළ නොහැක. (ඔබට සමහරක් මග හැරී ඇත - එසේම). For loop වැරදියි (අස්ථානගතව -r) සහ එයින් අදහස් වන්නේ ලිපිගොනු තුළ පාස් කිහිපයක් සෑදීම සහ sed ස්ක්‍රිප්ටයකින් කිසිදු ප්‍රතිලාභයක් එක් නොකිරීමයි.
ස්ටෙෆාන් චසෙලාස්

7
dterdon ආදේශක විධානයෙන් --පසුව sed -iසහ පෙර ඇඟවුම් කරන්නේ කුමක්ද?
ගීක්

6
Ee ගීක් එය පොසික්ස් දෙයක්. එය විකල්පවල අවසානය සංකේතවත් කරන අතර ආරම්භ වන තර්ක ඉදිරිපත් කිරීමට ඔබට ඉඩ සලසයි -. එය භාවිතා කිරීම මඟින් විධාන වැනි නම් සහිත ලිපිගොනු වල ක්‍රියා කරන බව සහතික කරයි -foo. එය නොමැතිව, -fවිකල්පයක් ලෙස විග්‍රහ කරනු ලැබේ.
ටර්ඩන්

2
Git ගබඩාවල ඇති පුනරාවර්තන විධාන සමහරක් ක්‍රියාත්මක කිරීමේදී ඉතා ප්‍රවේශම් වන්න. උදාහරණයක් ලෙස, මෙම පිළිතුරේ 1 වන කොටසේ දක්වා ඇති විසඳුම් ඇත්ත වශයෙන්ම .gitනාමාවලියක අභ්‍යන්තර git ගොනු වෙනස් කරනු ඇති අතර ඇත්ත වශයෙන්ම ඔබගේ පිටවීම අවුල් කරයි. නම අනුව නිශ්චිත නාමාවලි තුළ / ක්‍රියාත්මක වීමට වඩා හොඳය.
පිස්ටෝස්

79

හොඳ r e pl acement ලිනක්ස් මෙවලමක් rpl වේ , එය මුලින් ලියනු ලැබුවේ ඩේබියන් ව්‍යාපෘතිය සඳහා වන අතර එබැවින් එය apt-get install rplඕනෑම ඩේබියන් ව්‍යුත්පන්න ඩිස්ට්‍රෝ එකකින් ලබා ගත හැකි අතර අනෙක් අයටද විය හැකිය, නමුත් වෙනත් ආකාරයකින් ඔබට tar.gzගොනුව SourgeForge වෙතින් බාගත හැකිය. .

භාවිතයට සරලම උදාහරණය:

 $ rpl old_string new_string test.txt

නූලට අවකාශයක් තිබේ නම් එය උද්ධෘත ලකුණු වල ඇතුළත් කළ යුතු බව සලකන්න. පෙරනිමියෙන් rplඇති කර ගැනීමේ පහසුකම් ප්රාග්ධන ලිපි නමුත් අයත් නැති සම්පූර්ණ වචන , එහෙත් ඔබ විකල්ප සමග මෙම පෙරනිමි වෙනස් කළ හැකිය -i(නඩුව නොසලකා) සහ -w(මුළු වචන). ඔබට බහු ගොනු නියම කළ හැකිය :

 $ rpl -i -w "old string" "new string" test.txt test2.txt

හෝ නාමාවලියෙහි ( ) සෙවීමට හෝ පුනරාවර්තන ලෙස ( ) සෙවීමට දිගු ( -x) සඳහන් කරන්න :-R

 $ rpl -x .html -x .txt -R old_string new_string test*

ඔබ ද සොයා / දී විස්ථාපනය කල හැකි අන්තර් මාදිලිය සමග-p (විමසුමේ) විකල්පය හැකිය:

ප්‍රතිදානය මඟින් ගොනු / නූල් ප්‍රතිස්ථාපනය කර ඇති සෙවුම් වර්ගය (/ සංවේදී, සම්පූර්ණ / අර්ධ වචන වලින්) පෙන්වයි, නමුත් එය -q( නිහ mode මාදිලියේ ) විකල්පය සමඟ නිහ be ව සිටිය හැකිය , නැතහොත් ඊටත් වඩා වාචිකව, ලැයිස්තුගත රේඛා අංක ලැයිස්තුගත කරන්න එක් එක් ගොනුව හා නාමාවලිය සමඟ ගැලපීම් -v( verbose mode ) විකල්පය .

මතක තබා ගත යුතු වෙනත් විකල්ප වන්නේ -e(ගෞරව ස්කේප්) regular expressions, එබැවින් ඔබට ටැබ් ( \t), නව රේඛා ( \n) යනාදිය සෙවිය හැකිය . බලහත්කාරයෙන් අවසර ලබා-f ගැනීමට පවා ඔබට භාවිතා කළ හැකිය (ඇත්ත වශයෙන්ම, පරිශීලකයාට ලිඛිත අවසර ඇති විට පමණි) සහ වෙනස් කිරීමේ වේලාවන් ආරක්ෂා කර ගැනීම සඳහා).-d

අවසාන වශයෙන්, හරියටම කුමක් කරයිදැයි ඔබට විශ්වාස නැත්නම්, -s( සමාකරණ ප්‍රකාරය ) භාවිතා කරන්න.


2
Sed වලට වඩා ප්‍රතිපෝෂණය හා සරල බව අනුව වඩා හොඳය. ගොනු නාමයන් මත ක්‍රියා කිරීමට එය ඉඩ දෙනු ඇතැයි මම ප්‍රාර්ථනා කරමි, එවිට එය පරිපූර්ණ වනු ඇත.
Kzqai

1
මම කැමතියි -s (simulate mode) :-)
m3nda

26

සෙවුම් කරන්නේ කෙසේද සහ බහු ගොනු හරහා ප්‍රතිස්ථාපනය කරන්නේ කෙසේද යන්න යෝජනා කරයි:

ඔබට සොයා ගැනීම සහ සෙඩ් කිරීම ද භාවිතා කළ හැකිය, නමුත් මෙම කුඩා පර්ල් රේඛාව මනාව ක්‍රියාත්මක වන බව මට පෙනී ගියේය.

perl -pi -w -e 's/search/replace/g;' *.php
  • -e යන්නෙන් පහත කේත රේඛාව ක්‍රියාත්මක කරන්න.
  • -i යන්නෙන් තැන සංස්කරණය කරන්න
  • -w අනතුරු ඇඟවීම් ලියන්න
  • ආදාන ගොනුව හරහා -p ලූප්, ස්ක්‍රිප්ට් එක යෙදූ පසු සෑම පේළියක්ම මුද්‍රණය කරයි.

මගේ හොඳම ප්‍රති results ල ලැබෙන්නේ perl සහ grep භාවිතා කිරීමෙනි (ගොනුවට සෙවුම් ප්‍රකාශනය ඇති බව සහතික කිරීම සඳහා)

perl -pi -w -e 's/search/replace/g;' $( grep -rl 'search' )

15

ඔබට Vim in Ex මාදිලිය භාවිතා කළ හැකිය:

වත්මන් ඩිරෙක්ටරියේ ඇති සියලුම ලිපිගොනු වල ALF නූල BRA සමඟ ආදේශ කරන්න?

for CHA in *
do
  ex -sc '%s/ALF/BRA/g' -cx "$CHA"
done

උප නාමාවලි සඳහාද එය පුනරාවර්තනයක් කරන්නේද?

find -type f -exec ex -sc '%s/ALF/BRA/g' -cx {} ';'

ගොනුවේ නම වෙනත් නූලකට ගැලපෙන්නේ නම් පමණක් ආදේශ කරන්න?

for CHA in *.txt
do
  ex -sc '%s/ALF/BRA/g' -cx "$CHA"
done

යම් සන්දර්භයක් තුළ නූල හමු වුවහොත් පමණක් ආදේශ කරන්න?

ex -sc 'g/DEL/s/ALF/BRA/g' -cx file

නූල නිශ්චිත රේඛා අංකයක තිබේ නම් ප්‍රතිස්ථාපනය කරන්න?

ex -sc '2s/ALF/BRA/g' -cx file

එකම ආදේශනයකින් බහු නූල් ආදේශ කරන්න

ex -sc '%s/\vALF|ECH/BRA/g' -cx file

විවිධ නූල් වෙනුවට විවිධ නූල් ආදේශ කරන්න

ex -sc '%s/ALF/BRA/g|%s/FOX/GOL/g' -cx file

15

මම මෙය භාවිතා කළෙමි:

grep -r "old_string" -l | tr '\n' ' ' | xargs sed -i 's/old_string/new_string/g'
  1. අඩංගු සියලුම ගොනු ලැයිස්තුගත කරන්න old_string.

  2. ප්‍රති line ලයක් ලෙස නව රේඛාව අවකාශයන් සමඟ ප්‍රතිස්ථාපනය කරන්න (එවිට ලිපිගොනු ලැයිස්තුව පෝෂණය කළ හැකිය sed.

  3. sedපැරණි නූල් නව වෙනුවට ආදේශ කිරීමට එම ලිපිගොනු මත ධාවනය කරන්න .

යාවත්කාලීන කිරීම: ඉහත ප්‍රති result ලය හිස් අවකාශයන් අඩංගු ගොනු නාමයන් මත අසාර්ථක වනු ඇත. ඒ වෙනුවට, භාවිතා කරන්න:

grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'


ඔබගේ ඕනෑම ගොනු නාමයක අවකාශ, ටැබ් හෝ නව රේඛා තිබේ නම් මෙය අසාර්ථක වන බව සලකන්න. භාවිතය grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'එය අත්තනෝමතික ගොනු නාම සමඟ කටයුතු කරයි.
terdon

ස්තූතියි යාලුවනේ. යාවත්කාලීනයක් එකතු කර පැරණි කේතයෙන් ඉවත්වීම නිසා මෙම හැසිරීම නොදන්නා කෙනෙකුට ප්‍රයෝජනවත් විය හැකි සිත්ගන්නාසුලු අවවාදයකි.
o_o_o--

7

පරිශීලකයාගේ දෘෂ්ටි කෝණයෙන් බලන කල, කාර්යය මනාව ඉටු කරන ලස්සන හා සරල යුනික්ස් මෙවලමකි qsubst. උදාහරණයක් වශයෙන්,

% qsubst foo bar *.c *.h

මගේ සියලුම සී ගොනු fooසමඟ ප්‍රතිස්ථාපනය barවේ. ලස්සන ලක්ෂණය වන්නේ qsubstඑය කරන්නේ විමසුම-වෙනුවට , එනම්, එය මට එක් එක් සිදුවීම පෙන්වන, fooමම එය විස්ථාපනය හෝ නැති කිරීමට අවශ්යයද යන්න කියලා. [ඔබට කොන්දේසි විරහිතව (ඉල්ලීමක් නැත) -goවිකල්පය සමඟ ප්‍රතිස්ථාපනය කළ හැකි අතර වෙනත් විකල්ප තිබේ, උදා: -wඔබට ප්‍රතිස්ථාපනය කිරීමට අවශ්‍ය නම්foo එය සම්පූර්ණ වචනයක් වූ විට .]

එය ලබා ගන්නේ කෙසේද: qsubstඩර් මවුස් (මැක්ගිල් වෙතින්) විසින් සොයා ගන්නා ලද අතර 1987 අගෝස්තු මාසයේදී comp.unix.sources 11 (7) වෙත පළ කරන ලදී. යාවත්කාලීන කරන ලද අනුවාදයන් පවතී. උදාහරණයක් ලෙස, නෙට්බීඑස්ඩී අනුවාදය qsubst.c,v 1.8 2004/11/01සම්පාදනය කර මගේ මැක් මත පරිපූර්ණව ක්‍රියාත්මක වේ.


3

ripgrep (විධාන නාමය rg) යනු grepමෙවලමකි, නමුත් සෙවීමට සහ ප්‍රතිස්ථාපනය කිරීමටද සහාය වේ.

$ cat ip.txt
dark blue and light blue
light orange
blue sky
$ # by default, line number is displayed if output destination is stdout
$ # by default, only lines that matched the given pattern is displayed
$ # 'blue' is search pattern and -r 'red' is replacement string
$ rg 'blue' -r 'red' ip.txt
1:dark red and light red
3:red sky

$ # --passthru option is useful to print all lines, whether or not it matched
$ # -N will disable line number prefix
$ # this command is similar to: sed 's/blue/red/g' ip.txt
$ rg --passthru -N 'blue' -r 'red' ip.txt
dark red and light red
light orange
red sky


rg ස්ථානීය විකල්පයට සහය නොදක්වයි, එබැවින් ඔබට එය තනිවම කිරීමට සිදුවේ

$ # -N isn't needed here as output destination is a file
$ rg --passthru 'blue' -r 'red' ip.txt > tmp.txt && mv tmp.txt ip.txt
$ cat ip.txt
dark red and light red
light orange
red sky


සාමාන්‍ය ප්‍රකාශන වාක්‍ය ඛණ්ඩ සහ විශේෂාංග සඳහා රස්ට් රීජෙක්ස් ප්‍රලේඛනය බලන්න . මෙම -Pස්විචය හැකි වනු ඇත PCRE2 රසය. rgපෙරනිමියෙන් යුනිකෝඩ් සඳහා සහය දක්වයි.

$ # non-greedy quantifier is supported
$ echo 'food land bark sand band cue combat' | rg 'foo.*?ba' -r 'X'
Xrk sand band cue combat

$ # unicode support
$ echo 'fox:αλεπού,eagle:αετός' | rg '\p{L}+' -r '($0)'
(fox):(αλεπού),(eagle):(αετός)

$ # set operator example, remove all punctuation characters except . ! and ?
$ para='"Hi", there! How *are* you? All fine here.'
$ echo "$para" | rg '[[:punct:]--[.!?]]+' -r ''
Hi there! How are you? All fine here.

$ # use -P if you need even more advanced features
$ echo 'car bat cod map' | rg -P '(bat|map)(*SKIP)(*F)|\w+' -r '[$0]'
[car] bat [cod] map


හරියට grep, -Fවිකල්පය ස්ථාවර නූල් ගැලපීමට ඉඩ දෙනු ඇත, එය sedක්‍රියාත්මක කළ යුතු යැයි මට හැඟෙන පහසු විකල්පයකි .

$ printf '2.3/[4]*6\nfoo\n5.3-[4]*9\n' | rg --passthru -F '[4]*' -r '2'
2.3/26
foo
5.3-29


තවත් පහසු විකල්පයක් වන්නේ -Uබහු රේඛා ගැලපීම සක්‍රීය කිරීමයි

$ # (?s) flag will allow . to match newline characters as well
$ printf '42\nHi there\nHave a Nice Day' | rg --passthru -U '(?s)the.*ice' -r ''
42
Hi  Day


rg dos-style ගොනු ද හැසිරවිය හැකිය

$ # same as: sed -E 's/\w+(\r?)$/123\1/'
$ printf 'hi there\r\ngood day\r\n' | rg --passthru --crlf '\w+$' -r '123'
hi 123
good 123


තවත් වාසියක් rgවන්නේ එය වඩා වේගවත් වීමට ඉඩ තිබීමයිsed

$ # for small files, initial processing time of rg is a large component
$ time echo 'aba' | sed 's/a/b/g' > f1
real    0m0.002s
$ time echo 'aba' | rg --passthru 'a' -r 'b' > f2
real    0m0.007s

$ # for larger files, rg is likely to be faster
$ # 6.2M sample ASCII file
$ wget https://norvig.com/big.txt    
$ time LC_ALL=C sed 's/\bcat\b/dog/g' big.txt > f1
real    0m0.060s
$ time rg --passthru '\bcat\b' -r 'dog' big.txt > f2
real    0m0.048s
$ diff -s f1 f2
Files f1 and f2 are identical

$ time LC_ALL=C sed -E 's/\b(\w+)(\s+\1)+\b/\1/g' big.txt > f1
real    0m0.725s
$ time rg --no-pcre2-unicode --passthru -wP '(\w+)(\s+\1)+' -r '$1' big.txt > f2
real    0m0.093s
$ diff -s f1 f2
Files f1 and f2 are identical

3

මට වියළි ධාවන විකල්පයක් සපයන යමක් අවශ්‍ය වූ අතර එය නැවත නැවතත් ග්ලෝබ් සමඟ වැඩ කරන අතර එය කිරීමට උත්සාහ කිරීමෙන් පසුව awkසහsed මම දුන්නා, ඒ වෙනුවට පිඹුරා එය කළා.

මෙම තිර රචනය සෙවුම් සඳහා glob රටාව (උදා: ගැලපෙන සියළුම ගොනු ඇත්තෙන් වෙනසට භාජනය --glob="*.html"විස්ථාපනය regex සමග regex හා ප්රතිස්ථාපනය කරනු සඳහා):

find_replace.py [--dir=my_folder] \
    --search-regex=<search_regex> \
    --replace-regex=<replace_regex> \
    --glob=[glob_pattern] \
    --dry-run

--search-regexඅනුරූප කෙටි විකල්පයක් වැනි සෑම දිගු විකල්පයක්ම , එනම් -s. -hසියලු විකල්ප බැලීමට ධාවනය කරන්න .

උදාහරණයක් ලෙස, මෙම සියලු දිනයන් ගියහොත් ඇත 2017-12-31කිරීමට 31-12-2017:

python replace.py --glob=myfile.txt \
    --search-regex="(\d{4})-(\d{2})-(\d{2})" \
    --replace-regex="\3-\2-\1" \
    --dry-run --verbose
import os
import fnmatch
import sys
import shutil
import re

import argparse

def find_replace(cfg):
    search_pattern = re.compile(cfg.search_regex)

    if cfg.dry_run:
        print('THIS IS A DRY RUN -- NO FILES WILL BE CHANGED!')

    for path, dirs, files in os.walk(os.path.abspath(cfg.dir)):
        for filename in fnmatch.filter(files, cfg.glob):

            if cfg.print_parent_folder:
                pardir = os.path.normpath(os.path.join(path, '..'))
                pardir = os.path.split(pardir)[-1]
                print('[%s]' % pardir)
            filepath = os.path.join(path, filename)

            # backup original file
            if cfg.create_backup:
                backup_path = filepath + '.bak'

                while os.path.exists(backup_path):
                    backup_path += '.bak'
                print('DBG: creating backup', backup_path)
                shutil.copyfile(filepath, backup_path)

            with open(filepath) as f:
                old_text = f.read()

            all_matches = search_pattern.findall(old_text)

            if all_matches:

                print('Found {} matches in file {}'.format(len(all_matches), filename))

                new_text = search_pattern.sub(cfg.replace_regex, old_text)

                if not cfg.dry_run:
                    with open(filepath, "w") as f:
                        print('DBG: replacing in file', filepath)
                        f.write(new_text)
                else:
                    for idx, matches in enumerate(all_matches):
                        print("Match #{}: {}".format(idx, matches))

                    print("NEW TEXT:\n{}".format(new_text))

            elif cfg.verbose:
                print('File {} does not contain search regex "{}"'.format(filename, cfg.search_regex))


if __name__ == '__main__':

    parser = argparse.ArgumentParser(description='''DESCRIPTION:
    Find and replace recursively from the given folder using regular expressions''',
                                     formatter_class=argparse.RawDescriptionHelpFormatter,
                                     epilog='''USAGE:
    {0} -d [my_folder] -s <search_regex> -r <replace_regex> -g [glob_pattern]

    '''.format(os.path.basename(sys.argv[0])))

    parser.add_argument('--dir', '-d',
                        help='folder to search in; by default current folder',
                        default='.')

    parser.add_argument('--search-regex', '-s',
                        help='search regex',
                        required=True)

    parser.add_argument('--replace-regex', '-r',
                        help='replacement regex',
                        required=True)

    parser.add_argument('--glob', '-g',
                        help='glob pattern, i.e. *.html',
                        default="*.*")

    parser.add_argument('--dry-run', '-dr',
                        action='store_true',
                        help="don't replace anything just show what is going to be done",
                        default=False)

    parser.add_argument('--create-backup', '-b',
                        action='store_true',
                        help='Create backup files',
                        default=False)

    parser.add_argument('--verbose', '-v',
                        action='store_true',
                        help="Show files which don't match the search regex",
                        default=False)

    parser.add_argument('--print-parent-folder', '-p',
                        action='store_true',
                        help="Show the parent info for debug",
                        default=False)

    config = parser.parse_args(sys.argv[1:])

    find_replace(config)

Here යනු ස්ක්‍රිප්ට් හි යාවත්කාලීන කරන ලද අනුවාදයක් වන අතර එය සෙවුම් වචන සහ විවිධ වර්ණවලින් ආදේශ කිරීම ඉස්මතු කරයි.


2
මට තේරෙන්නේ නැහැ ඇයි ඔයා මේ සංකීර්ණ දෙයක් කරන්නේ කියලා. පුනරාවර්තනය සඳහා, bash (හෝ ඔබේ කවචයට සමාන) globstarවිකල්පය සහ **ග්ලෝබ් භාවිතා කරන්න find. වියළි ධාවනය සඳහා, භාවිතා කරන්න sed. ඔබ -iවිකල්පය භාවිතා නොකරන්නේ නම් , එයින් කිසිදු වෙනසක් සිදු නොවේ. උපස්ථ භාවිතය සඳහා sed -i.bak(හෝ perl -i .bak); නොගැලපෙන ගොනු සඳහා, භාවිතා කරන්න grep PATTERN file || echo file. කවදාවත් කවචයට එය කිරීමට ඉඩ නොදී පයිතන් ගෝලීයව පුළුල් කරන්නේ ඇයි? script.py --glob=foo*සාධාරණ වෙනුවට ඇයි script.py foo*?
ටර්ඩන්

1
මගේ හේතුව ඉතා සරල ය: (1) සියල්ලටම වඩා, නිදොස්කරණය කිරීමේ පහසුව; (2) සහයෝගය ප්රජාව (3) නොදැන සමග පමණක් තනි හොඳින් වාර්තා මෙවලම භාවිතා කර sedහා awkහොඳින් හා ඔවුන් ප්රගුණ මත අමතර කාලය වැය කිරීමට අකමැති වීම, (4) කියවීමේ පහසුව, (5) මෙම විසඳුම ද-POSIX නොවන පද්ධති මත වැඩ කරනු ඇත (මට එය අවශ්‍ය බව නොව වෙනත් අයෙකු විය හැකිය).
ccpizza

0

මෙන්න මම ගොනුවක් වෙනස් කිරීමට යන්නේgrep දැයි පැවසීමට භාවිතා කරමි (එබැවින් වෙනස් කළ රේඛා ගණන සහ ප්‍රතිස්ථාපනය අවසානයේ ප්‍රතිදානය සඳහා ගණනය කළ හැකිය), පසුව මම ඇත්ත වශයෙන්ම ගොනුව වෙනස් කිරීමට භාවිතා කරමි . තනි මාර්ගය දැනුම් දී භාවිතය ඉතා අවසන් පහත බෑෂ් කාර්යය:sedsed

replace_str Bash ශ්‍රිතය

භාවිතය :

gs_replace_str "regex_search_pattern" "replacement_string" "file_path"

බෑෂ් කාර්යය:

# Usage: `gs_replace_str "regex_search_pattern" "replacement_string" "file_path"`
gs_replace_str() {
    REGEX_SEARCH="$1"
    REPLACEMENT_STR="$2"
    FILENAME="$3"

    num_lines_matched=$(grep -c -E "$REGEX_SEARCH" "$FILENAME")
    # Count number of matches, NOT lines (`grep -c` counts lines), 
    # in case there are multiple matches per line; see: 
    # /superuser/339522/counting-total-number-of-matches-with-grep-instead-of-just-how-many-lines-match/339523#339523
    num_matches=$(grep -o -E "$REGEX_SEARCH" "$FILENAME" | wc -l)

    # If num_matches > 0
    if [ "$num_matches" -gt 0 ]; then
        echo -e "\n${num_matches} matches found on ${num_lines_matched} lines in file"\
                "\"${FILENAME}\":"
        # Now show these exact matches with their corresponding line 'n'umbers in the file
        grep -n --color=always -E "$REGEX_SEARCH" "$FILENAME"
        # Now actually DO the string replacing on the files 'i'n place using the `sed` 
        # 's'tream 'ed'itor!
        sed -i "s|${REGEX_SEARCH}|${REPLACEMENT_STR}|g" "$FILENAME"
    fi
}

උදාහරණයක් ලෙස ඔබේ ~ / .bashrc ගොනුවේ තබන්න. ඔබේ පර්යන්තය වසා නැවත විවෘත කර එය භාවිතා කරන්න.

උදාහරණයක්:

වෙනුවට doසමග bo"හොඳින්" "Boing" වෙන්නේ එසේ බව (මම දන්නවා, අපි ඔවුන්ට නිර්මාණය නොවන අක්ෂර වින්යාසය සවි කළ යුතු :)):

$ gs_replace_str "do" "bo" test_folder/test2.txt 

9 matches found on 6 lines in file "test_folder/test2.txt":
1:hey how are you doing today
2:hey how are you doing today
3:hey how are you doing today
4:hey how are you doing today  hey how are you doing today  hey how are you doing today  hey how are you doing today
5:hey how are you doing today
6:hey how are you doing today?
$SHLVL:3 

ප්‍රතිදානයේ තිර රුව:

රූප විස්තරය මෙහි ඇතුළත් කරන්න

යොමුව:

  1. /superuser/339522/counting-total-number-of-matches-with-grep-instead-of-just-how-many-lines-match/339523#339523
  2. /programming/12144158/how-to-check-if-sed-has-changed-a-file/61238414#61238414
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.