Поиск и замена в bash с использованием регулярных выражений
Я видел этот пример:
hello=ho02123ware38384you443d34o3434ingtod38384day
echo ${hello//[0-9]/}
Который следует за этим синтаксисом: ${variable//pattern/replacement}
К сожалению, поле pattern
похоже не поддерживает полный синтаксис regex (если я использую .
или \s
, например, он пытается сопоставить буквенные символы).
Как я могу искать/заменять строку, используя полный синтаксис regex?
Ответы
Ответ 1
Используйте sed:
MYVAR=ho02123ware38384you443d34o3434ingtod38384day
echo "$MYVAR" | sed -e 's/[a-zA-Z]/X/g' -e 's/[0-9]/N/g'
# prints XXNNNNNXXXXNNNNNXXXNNNXNNXNNNNXXXXXXNNNNNXXX
Обратите внимание, что последующие -e
обрабатываются по порядку. Кроме того, флаг g
для выражения будет соответствовать всем вхождениям на входе.
Вы также можете выбрать свой любимый инструмент, используя этот метод, например, perl, awk, например:
echo "$MYVAR" | perl -pe 's/[a-zA-Z]/X/g and s/[0-9]/N/g'
Это может позволить вам делать больше творческих соответствий... Например, в приведенном выше фрагменте замена чисел не будет использоваться, если не будет совпадения в первом выражении (из-за ленивости and
оценки). И, конечно, у вас есть полная языковая поддержка Perl для выполнения ваших ставок...
Ответ 2
Фактически может выполняться в чистом bash:
hello=ho02123ware38384you443d34o3434ingtod38384day
re='(.*)[0-9]+(.*)'
while [[ $hello =~ $re ]]; do
hello=${BASH_REMATCH[1]}${BASH_REMATCH[2]}
done
echo "$hello"
... дает...
howareyoudoingtodday
Ответ 3
Эти примеры также работают в bash не нужно использовать sed:
#!/bin/bash
MYVAR=ho02123ware38384you443d34o3434ingtod38384day
MYVAR=${MYVAR//[a-zA-Z]/X}
echo ${MYVAR//[0-9]/N}
вы также можете использовать выражения скобок символьного класса
#!/bin/bash
MYVAR=ho02123ware38384you443d34o3434ingtod38384day
MYVAR=${MYVAR//[[:alpha:]]/X}
echo ${MYVAR//[[:digit:]]/N}
Выход
XXNNNNNXXXXNNNNNXXXNNNXNNXNNNNXXXXXXNNNNNXXX
То, что @Lanaru хотел узнать, если я правильно понял вопрос, почему "полные" или расширения PCRE \s\S\w\W\d\D
и т.д. не работают как поддерживаемые в php ruby python и т.д. Эти расширения от Perl-совместимых регулярные выражения (PCRE) и могут быть несовместимы с другими формами регулярных выражений на основе оболочки.
Они не работают:
#!/bin/bash
hello=ho02123ware38384you443d34o3434ingtod38384day
echo ${hello//\d/}
#!/bin/bash
hello=ho02123ware38384you443d34o3434ingtod38384day
echo $hello | sed 's/\d//g'
вывод со всеми буквальными "d" символами удален
ho02123ware38384you44334o3434ingto38384ay
но следующее работает как ожидалось
#!/bin/bash
hello=ho02123ware38384you443d34o3434ingtod38384day
echo $hello | perl -pe 's/\d//g'
Выход
howareyoudoingtodday
Надеюсь, что это немного разъяснит ситуацию, но если вы еще не запутались, почему бы вам не попробовать это в Mac OS X, где включен флаг REG_ENHANCED:
#!/bin/bash
MYVAR=ho02123ware38384you443d34o3434ingtod38384day;
echo $MYVAR | grep -o -E '\d'
В большинстве вариантов * nix вы увидите только следующий вывод:
d
d
d
NJoy!
Ответ 4
Если вы делаете повторные вызовы и занимаетесь производительностью, этот тест показывает, что метод BASH ~ 15 раз быстрее, чем forking для sed и, вероятно, любой другой внешний процесс.
hello=123456789X123456789X123456789X123456789X123456789X123456789X123456789X123456789X123456789X123456789X123456789X
P1=$(date +%s)
for i in {1..10000}
do
echo $hello | sed s/X//g > /dev/null
done
P2=$(date +%s)
echo $[$P2-$P1]
for i in {1..10000}
do
echo ${hello//X/} > /dev/null
done
P3=$(date +%s)
echo $[$P3-$P2]
Ответ 5
Используйте [[:digit:]]
(обратите внимание на двойные скобки) в качестве шаблона:
$ hello=ho02123ware38384you443d34o3434ingtod38384day
$ echo ${hello//[[:digit:]]/}
howareyoudoingtodday
Просто хотел обобщить ответы (особенно @nickl- fooobar.com/info/66978/...).