Поиск без учета регистра и замена на 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'

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

Ответ 1

Для ясности: в macOS - с Mojave (10.14) - sed - которая является реализацией BSD - НЕ поддерживается сопоставление без учета регистра - трудно поверить, но это правда, ранее принятый ответ, который сам показывает команду GNU sed, получил этот статус из-за решения perl -based, упомянутого в комментариях.

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

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

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

Ответ 2

Editor note: This solution does not work on macOS (out of the box), because it only applies to GNU [TG40], whereas macOS comes with BSD [TG41].

Прописать "я".

sed 's/foo/bar/I' file

Ответ 3

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

Ответ 4

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

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

Ответ 5

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/
    

Ответ 6

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

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

grep -i -l -r foo ./* 

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

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 позволяет просматривать только файлы с целевым текстом (таким образом, вероятно, это может повысить производительность и скорость)

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

Ответ 7

Если вы делаете сопоставление с шаблоном первым, например,

/pattern/s/xx/yy/g

Затем вы хотите поставить I после шаблона:

/pattern/Is/xx/yy/g

Пример:

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

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

Ответ 8

sed 's/string1/string2/Ig'

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