У мене є "Я люблю Сузі і виходжу заміж" і хочу змінити "Сузі" на "Сару".
#!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
# do something...
Результат повинен бути таким:
firstString="I love Sara and Marry"
У мене є "Я люблю Сузі і виходжу заміж" і хочу змінити "Сузі" на "Сару".
#!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
# do something...
Результат повинен бути таким:
firstString="I love Sara and Marry"
Відповіді:
Щоб замінити перше виникнення шаблону заданим рядком, використовуйте :${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 Reference Manual , §3.5.3 "Shell Параметр Expansion" .)
Зауважте, що ця функція не визначена POSIX - це розширення Bash - тому не всі оболонки Unix реалізують її. Для відповідної документації POSIX див . Технічні стандартні бази відкритої групи, випуск 7 , том Shell & Utilities , §2.6.2 "Розширення параметрів" .
\n
в цьому контексті буде представляти себе, а не новий рядок. Я не маю під рукою Bash прямо зараз для тестування, але ви повинні мати можливість написати щось на кшталт $STRING="${STRING/$'\n'/<br />}"
,. (Хоча ви, мабуть, хочете STRING//
- замініть все - замість просто STRING/
.)
echo ${my string foo/foo/bar}
. Вам знадобитьсяinput="my string foo"; echo ${input/foo/bar}
//
прямої згадки , вона згадує, що відбувається "Якщо шаблон починається з /
" "(що навіть не є точним, оскільки решта цього речення передбачає, що додатково /
насправді не є частиною модель) - але я не знаю жодного кращого джерела.
Це можна зробити повністю за допомогою маніпуляції з рядком 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"
Для Dash всі попередні повідомлення не працюють
Рішення, sh
сумісне з POSIX :
result=$(echo "$firstString" | sed "s/Suzi/$secondString/")
result=$(echo $firstString | sed "s/Suzi/$secondString/g")
echo
аргументи навколо аргументу. Він оманливо працює без цитування простих рядків, але легко переривається на будь-який нетривіальний вхідний рядок (нерегулярний інтервал, метахарактеристики оболонки тощо).
спробуйте це:
sed "s/Suzi/$secondString/g" <<<"$firstString"
Краще використовувати 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
містить косої риси, але це нічого не порушило.
Подальше читання: Розширений посібник із написання сценарію .
Якщо використання sed
є обов'язковим, обов'язково уникайте кожного персонажа .
sed
з pwd
командою , щоб уникнути визначення нової змінної кожен раз , коли мої власні $PS1
пробіги. Чи пропонує Bash більш загальний спосіб, ніж магічні змінні, використовувати вихід команди для заміни рядків? Що стосується вашого коду, я повинен був уникнути, ~
щоб утримати Bash від його розширення на $ HOME. Крім того, що робить #
ваша команда?
~
": зауважте, як я цитував речі. Не забудьте завжди цитувати речі! І це не працює лише для магічних змінних: будь-яка змінна здатна замінювати, отримувати довжину рядка та інше в межах bash. Поздоровлення про те, що ви намагаєтеся $PS1
швидко: вам також може бути цікаво, $PROMPT_COMMAND
чи вам зручніше в іншій мові програмування та хочете кодувати складений підказку.
echo "${PWD/#$HOME/~}"
не замінить мій $HOME
з ~
. Заміна ~
з \~
або '~'
роботи. Будь-яка з цих робіт на Bash 4.2.53 на іншому дистрибутиві. Чи можете ви, будь ласка, оновити свою публікацію, щоб запропонувати цитату чи уникнути ~
кращої сумісності? Що я мав на увазі під своїм "магічним змінним" питанням: чи можу я використовувати підстановку змінної Баша на, наприклад, на виході uname
без збереження спочатку як змінної? Що стосується моєї особистої $PROMPT_COMMAND
, то це складно .
Якщо завтра ви вирішите, що ви не любите одружуватися, то її також можна замінити:
today=$(</tmp/lovers.txt)
tomorrow="${today//Suzi/Sara}"
echo "${tomorrow//Marry/Jesica}" > /tmp/lovers.txt
Має бути 50 способів залишити коханого.
Оскільки я не можу додати коментар. @ruaka Щоб зробити приклад більш читабельним, напишіть його так
full_string="I love Suzy and Mary"
search_string="Suzy"
replace_string="Sara"
my_string=${full_string/$search_string/$replace_string}
or
my_string=${full_string/Suzy/Sarah}
Чистий POSIX метод оболонки, який в відміну від Roman Kazanovskyi «s sed
-На відповіді не вимагає ніяких зовнішніх інструментів, тільки власні рідні оболонкових розширення параметрів . Зауважте, що довгі імена файлів зводяться до мінімуму, тому код краще вписується в один рядок:
f="I love Suzi and Marry"
s=Sara
t=Suzi
[ "${f%$t*}" != "$f" ] && f="${f%$t*}$s${f#*$t}"
echo "$f"
Вихід:
I love Sara and Marry
Як це працює:
Видаліть найменший шаблон суфіксу. "${f%$t*}"
повертає " I love
", якщо суфікс $t
" Suzi*
" знаходиться в $f
" ". I love
Suzi and Marry
Але якщо t=Zelda
, тоді "${f%$t*}"
нічого не видаляє, і повертає весь рядок " I love Suzi and Marry
".
Це використовується для тестування, якщо він $t
знаходиться в, $f
з [ "${f%$t*}" != "$f" ]
яким буде оцінено як істинне, якщо $f
рядок містить " Suzi*
", а помилково, якщо ні.
Якщо тест повернеться істинним , побудуйте потрібний рядок за допомогою " " Найменшого шаблону суфіксів ${f%$t*}
" I love
" та " Видалити найменший шаблон префікса ${f#*$t}
" and Marry
", з 2-й рядком $s
" Sara
"між ними.
Я знаю, що це старе, але оскільки ніхто не згадував про використання awk:
firstString="I love Suzi and Marry"
echo $firstString | awk '{gsub("Suzi","Sara"); print}'
echo [string] | sed "s/[original]/[target]/g"