Регистро-независимого поиска и замены с помощью sed


Я пытаюсь использовать sed для извлечения текста из файла журнала.

Я могу сделать поиск и замену без особых проблем:

sed 's/foo/bar/' mylog.txt

тем не менее, я хочу сделать поиск без учета регистра. Из того, что я погуглил, это похоже на добавление i до конца команда должна работать:

sed 's/foo/bar/i' mylog.txt
, это дает мне сообщение об ошибке:
sed: 1: "s/foo/bar/i": bad flag in substitute command: 'i'

что здесь не так, и как это исправить?

Я на macOS, в случае вопросы.

8 64

8 ответов:

чтобы было понятно: On macOS - по состоянию на Сьерра (10.12) -sed - это BSD реализация-не поддерживает сопоставление без учета регистра - трудно поверить, но это правда. Элемент ранее принятый ответ, что само по себе показывает GNUsed команда, получила этот статус из-за perl - решение на основе упомянутых в комментариях.

чтобы сделать это Perl solution работа с символы также, через UTF-8, используйте что-то вроде:

perl -C -Mutf8 -pe 's/öœ/oo/i' <<< "FÖŒ" # -> "Foo"
  • -C включает поддержку UTF-8 для потоков и файлов, предполагая, что текущая локаль основана на UTF-8.
  • -Mutf8 говорит Perl интерпретировать исходный код как UTF-8 (в этом случае строка передается в -pe) - это более короткий эквивалент более многословным -e 'use utf8;'.спасибо, Марк Рид

(обратите внимание, что используя awk тоже не вариант, а awk на macOS (т. е. BWK awk, а.к.а. BSD awk) кажется, совершенно не знают о местах вообще-его tolower() и toupper() функции игнорируют внешние символы (и sub()/gsub() не имеют флагов нечувствительности к регистру для начала).)

заглавная буква "I".

sed 's/foo/bar/I' file

еще один обход для sed на Mac OS X это установить gsedиз MacPorts или HomeBrew, а затем создать псевдоним sed='gsed'.

версия для Mac sed кажется немного ограниченным. Один из способов обойти это-использовать контейнер linux (через Docker), который имеет полезную версию sed:

cat your_file.txt | docker run -i busybox /bin/sed -r 's/[0-9]{4}/****/Ig'

The sed FAQ адресов, тесно связанных с учетом регистра поиск. Он указывает, что a) многие версии sed поддерживают флаг для него и b) это неудобно делать в sed, вы должны скорее использовать awk или Perl.

но чтобы сделать это в POSIX sed, они предлагают три варианта (адаптированные для замены здесь):

  1. преобразование в верхний регистр и сохранение исходной строки в пространстве удержания; это не будет работать для замен, хотя, как исходное содержимое будет восстановлено перед печатью, поэтому оно подходит только для вставки или добавления строк на основе совпадения без учета регистра.

  2. возможно, возможности ограничены FOO,Foo и foo. Они могут быть покрыты

    s/FOO/bar/;s/[Ff]oo/bar/
    
  3. для поиска всех возможных совпадений можно использовать скобочные выражения для каждого символа:

    s/[Ff][Oo][Oo]/bar/
    

у меня была аналогичная потребность, и я придумал это:

эта команда просто найти все файлы:

grep -i -l -r foo ./* 

это один, чтобы исключить this_shell.sh (в случае, если вы поместите команду в скрипт с именемthis_shell.sh), tee вывод на консоль, чтобы увидеть, что произошло, а затем использовать sed на каждое имя файла, найденное для замены текста foo на bar:

grep -i -l -r --exclude "this_shell.sh" foo ./* | tee  /dev/fd/2 | while read -r x; do sed -b -i 's/foo/bar/gi' "$x"; done 

Я выбрал этот метод, так как мне не понравилось, что все временные метки изменились для файлов нет модифицированный. подача результата grep позволяет просматривать только файлы с целевым текстом (таким образом, вероятно, может улучшить производительность / скорость)

Не забудьте сделать резервную копию файлов и проверить перед использованием. Может не работать в некоторых средах для файлов со встроенными помещениями. (?)

если вы делаете сопоставление шаблонов в первую очередь, например,

/pattern/s/xx/yy/g

тогда вы хотите поставить I модель:

/pattern/Is/xx/yy/g

пример:

echo Fred | sed '/fred/Is//willma/g'

возвращает willma, без I, он возвращает строку нетронутой (Fred).

sed 's/string1/string2/Ig'

капитал I - это опция, которая полезна для поиска строки независимо от чувствительности к регистру.