Використання sed та grep / egrep для пошуку та заміни


97

Я використовую, egrep -Rа потім регулярний вираз, що містить близько 10 об'єднань, наприклад, як: .jpg | .png | .gifі т.д. Це працює добре, тепер я хотів би замінити всі знайдені рядки на.bmp

Я думав про щось подібне

egrep -lR "\.jpg|\.png|\.gif" . | sed "s/some_expression/.jpg/" file_it_came_form

отже, питання тут полягає в тому, як мені зробити подібний регулярний вираз об'єднання sedі як сказати йому, щоб зберегти зміни у файлі, з якого він отримав вхідні дані.


2
Я знайшов це питання під час пошуку способів пошуку та заміни кількох файлів в ієрархії каталогів. Для інших в моїй ситуації спробуйте rpl .
titaniumdecoy

дякую, rpl працює, і це дуже легко запам'ятати .. просто rpl old_string new_string target_files.
cesarpachon

Відповіді:


183

Використовуйте цю команду:

egrep -lRZ "\.jpg|\.png|\.gif" . \
    | xargs -0 -l sed -i -e 's/\.jpg\|\.gif\|\.png/.bmp/g'
  • egrep: знайти відповідні рядки за допомогою розширених регулярних виразів

    • -l: лише список відповідних імен файлів

    • -R: пошук рекурсивно через усі задані каталоги

    • -Z: використовувати \0як роздільник записів

    • "\.jpg|\.png|\.gif": відповідати одній із рядків ".jpg", ".gif"або".png"

    • .: розпочати пошук у поточному каталозі

  • xargs: виконати команду з аргументом stdin

    • -0: використовувати \0як роздільник записів. Це важливо для узгодження -Zз egrepі щоб не вводити в оману пробіли та нові рядки у іменах вхідних файлів.

    • -l: використовуйте один параметр на команду як параметр

  • sed: S Tream ред itor

    • -i: замініть вхідний файл вихідним без створення резервної копії

    • -e: використовуйте наступний аргумент як вираз

    • 's/\.jpg\|\.gif\|\.png/.bmp/g': Замінити всі входження рядків ".jpg", ".gif"або ".png"з".bmp"


це все працює, крім | в осідній частині. Я не розумію, чому, хоча, оскільки це має сенс ... -l частина xargs видавала мені помилки, тож я її видалив, чи може це бути пов'язане?
Орі

Я виявив, що ця команда додає новий рядок до кінця всіх файлів, які вона обробляє.
titaniumdecoy

@titanumdecoy: Я не зміг відтворити таку поведінку. яку версію sed ви використовували і на якій ОС ви?
Девід Шмітт,

1
@DavidSchmitt: Ви, мабуть, хочете використовувати sed -rдля розширених регулярних виразів. У цей момент шаблон буде відповідати використаному в egrep, і ви можете поставити його в змінну для повторного використання.
bukzor

ця команда врятувала мені години роботи з копіювання файлів заголовків із мого додатка для бібліотеки, яку я створив. Це дивовижно :) Ось команда, яку я використав egrep -lRZ "\ .h $". | xargs -0 tar -cvf headers.tar | (cp headers.tar headers; cd headers; tar xf headers.tar;)
The Lazy Coder

11

Чесно кажучи, наскільки я люблю sed для відповідних завдань, це, безумовно, завдання для perl - воно справді більш потужне для такого роду одноклассників, особливо "записувати його назад, звідки воно береться" ( -iперемикач perl робить це для Ви, і, можливо, також дозволяє зберігати стару версію, наприклад, із додаванням .bak, просто використовуйте -i.bakзамість цього).

perl -i.bak -pe 's/\.jpg|\.png|\.gif/.jpg/

а не хитромудра робота в sed (якщо навіть можливо там) або awk ...


6
sed використовує -i, як і perl.
Stobor

@Stobor - Клянусь, у мене були проблеми, коли операція perl, коли я подавала рядок заміни регулярних виразів, робила саме те, що я хотіла, на відміну від sed, навіть якщо я дала опцію регулярного sedвиразу. він мав обмеження.
meder omuraliev

10

Ще один спосіб зробити це

find . -name *.xml -exec sed -i "s/4.6.0-SNAPSHOT/5.0.0-SNAPSHOT/" {} \;

Деякі довідки щодо наведеної команди

Знахідка зробить пошук для вас у поточному каталозі, позначеному .

-name ім'я файлу в моєму випадку його pom.xml може дати символи підстановки.

-exec виконати

sed редактор потоку

-i ігнорувати регістр

s є заміною

/4.6.0.../ Рядок для пошуку

/5.0.0.../ Рядок, що підлягає заміні


можливо, не такий потужний - але мені це набагато легше зрозуміти, ніж прийнята відповідь
icc97,

5

Я не міг отримати жодної з команд на цій сторінці, щоб вона працювала для мене: рішення sed додало новий рядок до кінця всіх оброблених файлів, і рішення perl не змогло прийняти достатньо аргументів з find. Я знайшов це рішення, яке чудово працює:

find . -type f -name '*.[hm]' -print0 
    | xargs -0 perl -pi -e 's/search_regex/replacement_string/g'

Це буде рекурсія вниз поточний дерева каталогів і замінити search_regexз replacement_stringв будь-яких файлах , що закінчуються на .hабо .m.

Раніше для цього я також використовував rpl .


0

спробуйте щось, використовуючи цикл for

 for i in `egrep -lR "YOURSEARCH" .` ; do echo  $i; sed 's/f/k/' <$i >/tmp/`basename $i`; mv /tmp/`basename $i` $i; done

не красиво, але слід робити.


3
xargs тут, безумовно, більш доречний.
Натан Фелман

1
а використання |while read iшаблону дозволило б транслювати потоки та уникнути обмежень довжини, коли результати egrep стають занадто довгими
Девід Шмітт,

0

Моїм випадком використання було те, що я хотів замінити foo:/Drive_Letterна. foo:/bar/baz/xyz У моєму випадку я зміг зробити це за допомогою наступного коду. Я був у тому самому каталозі, де було багато файлів.

find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'

сподівання, що допомогло.

ОНОВЛЕННЯ s | foo: / Drive_letter: | foo: / ba / baz / xyz | g


Ви можете використовувати інші роздільники для команди sed, і це робить імена шляхів набагато приємнішими:sed 's|foo:/Drive_letter:|foo:/ba/baz/xyz|g'
Кевін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.