$ printf '%s\n' "$str"
abc|def
ghi|jkl
$ printf '%s\n' "${str%\|*}"'`'"${str##*\|}"
abc|def
ghi`jkl
${str%\|*}
заменяется на строку с последним |
и всем после него удаленным. ${str##*\|}
заменяется на строку с последним |
и всем, что было до него. Комбинация вышеуказанных двух подстановок параметров с `
в -между ними дает результирующую строку.
Вы можете использовать тот факт, что .*
жадный:
sed 's/\(.*\)|/\1`/'
Или используйте:
sed 's/|\([^|]*\)$/`\1/'
Для сопоставления с |
, за которым следует что-то, что не содержит |
, до конца строки, как уже было показано Тоби, но этот подход работает только для замены отдельных символов.
Чтобы заменить его в многострочной строковой переменной оболочки, в GNU sed
вы можете использовать параметр -z
, который обрабатывает ввод как с разделителями NUL, а не с разделителями новой строки:
var=$(printf %s "$var" | sed -z '...')
Другим подходом может быть выполнение подстановки с использованием стандартных операторов раскрытия параметров:
case $var in
(*'|'*) var=${var%'|'*}'`'${var##*'|'}
esac
Или с этими sed
командами, переведенными в их эквивалент оболочки:
Вksh93
:
var=${var/@(*)'|'/\1'`'}
var=${var/%'|'*([^'|'])/'`'\1}
Вbash
(предполагается, что строка не содержит последовательностей байтов, не образующих допустимых символов в текущей локали):
re='(.*)\|(.*)'
[[ $var =~ $re ]] && var=${BASH_REMATCH[1]}'`'${BASH_REMATCH[2]}
Вzsh
:
set -o extendedglob
var=${var/(#b)(*)'|'/$match[1]'`'}
var=${var/%(#b)'|'([^'|']#)/'`'$match[1]}
Вы можете передать через rev
, заменить первое вхождение, а затем снова через rev
:
rev | sed -e 's/|/`/' | rev
В качестве альтернативы, в чистом sed
вы хотите заменить |
, за которым следует что-либо, кроме |
, на `
, за которым следует та же последовательность:
sed -e 's/|\([^|]*\)$/`\1/'
Я бы сказал, что первый из них легче читать и понимать.