Замена некоторых символов в строке другим символом

279

У меня есть строка, подобная AxxBCyyyDEFzzLMN, и я хочу заменить все вхождения x , y и z на _ .

Как мне этого добиться?

Я знаю, что echo "$string" | tr 'x' '_' | tr 'y' '_'это сработает, но я хочу сделать это за один раз, без использования труб.

Amarsh
источник
Вы хотели заменить любую последовательность последовательных x, y или z одним подчеркиванием, или вы хотели заменить каждое x, y или z одним подчеркиванием? Кроме того, как насчет смешанных последовательностей, как AxyzB? Три подчеркивания или одно?
Дэвид З
tr '[xyz]'заменит [и ]тоже. Аргумент должен быть просто списком символов (хотя диапазоны вроде бы a-zв порядке, а в некоторых реализациях классы символов POSIX вроде [:digit:]).
tripleee

Ответы:

329
echo "$string" | tr xyz _

заменит каждое вхождение x, yили zс _, что дает A__BC___DEF__LMNв вашем примере.

echo "$string" | sed -r 's/[xyz]+/_/g'

заменит повторяющиеся вхождения x, yили zс одним _, давая A_BC_DEF_LMNв вашем примере.

jkasnicki
источник
19
На Mac я получил следующее: sed: недопустимая опция - r использование: sed script [-Ealn] [-i расширение] [файл ...] sed [-Ealn] [-i расширение] [-e скрипт]. .. [-f script_file] ... [file ...]
catanore
У меня есть строка, которая содержит ,[]{}()~символы. Я хочу заменить его каждым экранированным символом, '\'каким образом я могу сделать это с помощью onehot?
Инкка
2
@halakala Mac поставляется с немного другой версией sed. Смотрите этот вопрос: unix.stackexchange.com/questions/13711/… Вместо этого вы можете установить «gnu-sed» с менеджером пакетов Homebrew, а затем использовать gsedбинарный файл: $ brew install gnu-sedзатем$ gsed -r 's/[xyz]+/_/g'
Джон Кэри,
6
На * BSD (и, следовательно, OSX) sed -E(в основном) эквивалентно sed -rна многих дистрибутивах Linux. Если вы используете sed 's/[xyz][xyz]*/_/g'эту опцию, вам не нужна эта опция. Конечно, это равносильно тому, tr -s xyz _что здесь нет реальной необходимости sed.
tripleee
@inckka Вы не можете использовать trдля этого. sed 's/[][{}()~,]/\\&/g'но на самом деле, задайте новый вопрос, если у вас есть дополнительный вопрос (не стесняйтесь ссылаться сюда для справки, конечно). Между прочим, ,и ~не являются метасимволами регулярных выражений (хотя в некоторых позициях ~расширяется $HOMEBash и некоторыми другими оболочками; shоднако не ).
tripleee
286

Использование расширения параметров Bash :

orig="AxxBCyyyDEFzzLMN"
mod=${orig//[xyz]/_}
Мэтью Флэшен
источник
7
Плохая замена
Алексей
1
@ Алексей, у меня работает пример (bash 4.3.11 (1) -релиз). Убедитесь, что вы используете bash. Другие оболочки могут не работать (хотя некоторые будут).
Мэтью Флашен
Спасибо @MatthewFlaschen. Это было именно то, что мне нужно, чтобы заменить sed для абсолютного пути в скрипте bash (замена / на \ /, так что sed принимает это).
Райан Г
1
@RyanG зачем использовать, sedесли в bash есть встроенная замена?
МестреЛион
@MestreLion Это могло произойти неправильно, но мне нужно было заменить стандартное имя переменной в группе файлов на абсолютный путь, для которого я использовал замену sed на месте. но вы не можете иметь "/" без экранирования в команде. Я связывал операции вместе в Bash. Разве это не лучший способ манипулировать строкой в ​​bash?
Райан G
111

Вы можете найти эту ссылку полезной:

http://tldp.org/LDP/abs/html/string-manipulation.html

В основном,

Чтобы заменить первое совпадение $ substring на $ replace:

${string/substring/replacement}

Чтобы заменить все совпадения $ substring на $ replace:

${string//substring/replacement}

РЕДАКТИРОВАТЬ: Обратите внимание, что это относится к переменной с именем $ string.

Дилан Дэниелс
источник
16
Обратите внимание, что это работает с переменной «string», а не с литеральной строкой.
mattdm
1
самый полезный, так как он содержит ссылку.
Os3
Лучшее и самое короткое решение.
северное дерево
8
read filename ;
sed -i 's/letter/newletter/g' "$filename" #letter

^ используйте столько, сколько вам нужно, и вы можете сделать свое собственное шифрование BASIC

Майкл
источник
5

Вот решение с расширением параметров оболочки, которое заменяет несколько смежных вхождений одним _:

$ var=AxxBCyyyDEFzzLMN
$ echo "${var//+([xyz])/_}"
A_BC_DEF_LMN

Обратите внимание, что шаблон требует расширенного сопоставления с шаблоном, включается с+(pattern)

shopt -s extglob

В качестве альтернативы, с -sопцией ("squeeze") tr:

$ tr -s xyz _ <<< "$var"
A_BC_DEF_LMN
Бенджамин В.
источник