Заменить одну подстроку на другую строку в сценарии оболочки

437

У меня есть "Я люблю Suzi и Marry", и я хочу изменить "Suzi" на "Sara".

#!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
# do something...

Результат должен быть таким:

firstString="I love Sara and Marry"
Теги:

6 ответов

789
Лучший ответ

Чтобы заменить первое вхождение шаблона заданной строкой, используйте ${parameter/pattern/string}:

#!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
echo "${firstString/Suzi/$secondString}"    # prints 'I love Sara and Marry'

Чтобы заменить все вхождения, используйте ${parameter//pattern/string}:

message='The secret code is 12345'
echo "${message//[0-9]/X}"           # prints 'The secret code is XXXXX'

(Это описано в Справочном руководстве Bash, §3.5.3 "Расширение параметров оболочки".)

Обратите внимание, что эта функция не указана POSIX - это расширение Bash, поэтому не все оболочки Unix реализуют ее. Информацию о соответствующей документации POSIX см. В разделе " Основные технические характеристики базового стандарта Open Group", выпуск 7, том "Шлюз и утилиты", §2.6.2 "Расширение параметров".

  • 2
    @ruakh как мне написать это утверждение с условием или. Просто, если я хочу заменить Сьюзи или Жениться на новую строку.
  • 2
    @ Priyatham51: для этого нет встроенной функции. Просто замените одно, затем другое.
Показать ещё 12 комментариев
124

Это можно сделать полностью с помощью bash манипуляции с строкой:

first="I love Suzy and Mary"
second="Sara"
first=${first/Suzy/$second}

Это заменит только первое вхождение; чтобы заменить их все, удвойте первую косую черту:

first="Suzy, Suzy, Suzy"
second="Sara"
first=${first//Suzy/$second}
# first is now "Sara, Sara, Sara"
  • 2
    Какой смысл иметь ответ, который дублирует принятый, а не редактировать принятый с глобальной опцией замены? И добавив, что регулярные выражения поддерживаются, пока у него. И объясняя, что случилось с «Плохой заменой». У тебя достаточно очков, @Kevin :)
47

попробуйте следующее:

 sed "s/Suzi/$secondString/g" <<<"$firstString"
  • 15
    Вам на самом деле не нужен Сед для этого; Bash изначально поддерживает такую замену.
  • 11
    Я думаю, это помечено как "bash", но пришло сюда, потому что нужно что-то простое для другой оболочки. Это хорошая и лаконичная альтернатива тому, что wiki.ubuntu.com/… выглядело так, как будто мне нужно.
Показать ещё 6 комментариев
39

Лучше использовать bash, чем sed если строки имеют символы RegExp.

echo ${first_string/Suzi/$second_string}

Он переносится в Windows и работает, по крайней мере, так же стара, как Bash 3.1.

Чтобы показать, что вам не нужно много волноваться об экранировании, позвольте включить это:

/home/name/foo/bar

В этом:

~/foo/bar

Но только если /home/name в начале. Нам не нужно sed !

Учитывая, что bash дает нам магические переменные $PWD и $HOME, мы можем:

echo "${PWD/#$HOME/\~}"

EDIT: Спасибо за Марка Хаферкампа в комментариях к заметке о цитировании/побеге ~. *

Обратите внимание, как переменная $HOME содержит слэши, но это ничего не сломало.

Дальнейшее чтение: Расширенный Bash-Scripting Guide.
Если использование sed является обязательным, обязательно избегайте каждого символа.

  • 0
    Этот ответ не позволил мне использовать sed с командой pwd чтобы избежать определения новой переменной каждый раз, когда запускается мой пользовательский $PS1 . Предоставляет ли Bash более общий способ, чем магические переменные, использовать вывод команды для замены строки? Что касается вашего кода, мне пришлось уйти от ~ чтобы Bash не расширил его до $ HOME. Кроме того, что делает # в вашей команде?
  • 1
    @MarkHaferkamp См. Ссылку «Рекомендуется дальнейшее чтение». Про "побег из ~ ": обратите внимание, как я цитировал материал. Не забывайте всегда цитировать вещи! И это работает не только для магических переменных: любая переменная способна к подстановкам, получению длины строки и многому другому в bash. Поздравляю с попыткой быстро $PROMPT_COMMAND $PS1 : вас также может заинтересовать $PROMPT_COMMAND если вам удобнее использовать другой язык программирования и вы хотите $PROMPT_COMMAND скомпилированное приглашение.
Показать ещё 5 комментариев
26

Для Dash все предыдущие сообщения не работают

Совместимое с POSIX sh решение:

result=$(echo "$firstString" | sed "s/Suzi/$secondString//")
  • 0
    Я получил это: $ echo $ (echo $ firstString | sed 's / Suzi / $ secondString / g') Я люблю $ secondString и Marry
  • 1
    @Qstnr_La использует двойные кавычки для подстановки переменных: result=$(echo $firstString | sed "s/Suzi/$secondString/g")
Показать ещё 2 комментария
8

Если завтра вы решите, что не любите Marry, ее тоже можно заменить:

today=$(</tmp/lovers.txt)
tomorrow="${today//Suzi/Sara}"
echo "${tomorrow//Marry/Jesica}" > /tmp/lovers.txt

Должно быть 50 способов оставить своего любовника.

  • 0
    :-Да, ты прав!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню