Поиск и замена без учета регистра на 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 ответов
чтобы быть ясным: On macOS - по состоянию на Сьерра (10.12) -sed
- это BSD реализация-не поддерживает сопоставление без учета регистраранее принятый ответ, который сам показывает GNU sed
команда, получила этот статус из-за perl
-решение уже упоминалось в комментариях.
чтобы сделать это решение на Perl работа с символы также, через UTF-8, используйте что-то вроде:
perl -C -Mutf8 -pe 's/öœ/oo/i' <<< "FÖŒ" # -> "Foo"
-
-C
включает поддержку UTF-8 для потоков и файлов, предполагая, что текущая локаль основана на UTF-8. -
-Mutf8
говорит Perl интерпретировать исходный код как UTF-8 (в этом случае строка передается в-pe
) - это более короткий эквивалент более многословным-e 'use utf8;'.
спасибо, Марк Рид!--22-->
(обратите внимание, что используя awk
также не является вариантом, as awk
на macOS (т. е. BWK awk, a.к. a. BSD awk), похоже, совершенно не знает о местах вообще-его tolower()
и toupper()
функции игнорируют иностранные символы (и sub()
/ gsub()
не имеют флагов нечувствительности к регистру для начала).)
еще одна работа-вокруг 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'
на sed FAQ адресов, тесно связанных с учетом регистра поиск. Он указывает, что a) многие версии sed поддерживают флаг для него и b) это неудобно делать в sed, вы должны скорее использовать awk или Perl.
но чтобы сделать это в POSIX sed, они предлагают три варианта (адаптированные для замены здесь):
преобразовать в верхний регистр и сохранить исходную строку в пространстве хранения; это не будет работать для подстановок, хотя, как исходный контент будет восстановлен перед печатью, поэтому он подходит только для вставки или добавления строк на основе совпадения без учета регистра.
-
возможно, возможности ограничены
FOO
,Foo
иfoo
. Они могут быть покрытыs/FOO/bar/;s/[Ff]oo/bar/
-
для поиска всех возможных совпадений можно использовать скобочные выражения для каждого символа:
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
- это опция, которая полезна для поиска строки независимо от чувствительности к регистру.