2

I'm trying to replace the last occurrence of a character within a multi line string variable.

I need to replace the last | with a `.

2

You could pipe through rev, replace the first occurrence, and then through rev again:

rev | sed -e 's/|/`/' | rev

Alternatively, in pure sed, you want to replace | followed by anything not including | with ` followed by the same sequence:

sed -e 's/|\([^|]*\)$/`\1/'

I'd argue that the first of those is easier to read and understand.

  • Thank you. But these expressions replace the last instance on each line. I'd like to replace the very last occurrence within the variable. – Chris Pavey Oct 30 '18 at 11:16
  • 2
    If you have GNU sed (likely, as you're on Linux), you can set the line separator to be the NUL character, using -z or --null-data, so your entire input will be considered as a single line. – Toby Speight Oct 30 '18 at 11:32
2

You can use the fact that .* is greedy:

sed 's/\(.*\)|/\1`/'

Or use:

sed 's/|\([^|]*\)$/`\1/'

To match on | followed by something that doesn't contain | til the end of line as already shown by Toby, but that approach only works for single character replacements.

To replace it in a multiline string shell variable, with GNU sed, you can use the -z option which treats the input as NUL delimited instead of newline delimited:

var=$(printf %s "$var" | sed -z '...')

Another approach would be to do the substitution using standard parameter expansion operators:

case $var in
  (*'|'*) var=${var%'|'*}'`'${var##*'|'}
esac

Or with those sed commands translated to their shell equivalent:

In ksh93:

var=${var/@(*)'|'/\1'`'}
var=${var/%'|'*([^'|'])/'`'\1}

In bash (assuming the string doesn't contain byte sequences not forming valid characters in the current locale):

re='(.*)\|(.*)'
[[ $var =~ $re ]] && var=${BASH_REMATCH[1]}'`'${BASH_REMATCH[2]}

In zsh:

set -o extendedglob
var=${var/(#b)(*)'|'/$match[1]'`'}

var=${var/%(#b)'|'([^'|']#)/'`'$match[1]}
  • Thank you. But these expressions replace the last instance on each line. I'd like to replace the very last occurrence within the variable. – Chris Pavey Oct 30 '18 at 11:16
  • @Chris, I had missed that part of your requirement. See edit. – Stéphane Chazelas Oct 30 '18 at 12:08
0
$ printf '%s\n' "$str"
abc|def
ghi|jkl
$ printf '%s\n' "${str%\|*}"'`'"${str##*\|}"
abc|def
ghi`jkl
  • ${str%\|*} expands to the string with the last | and everything after it removed.
  • ${str##*\|} expands to the string with the last | and everything before it removed.

The combination of the above two parameter substitutions, with a ` in-between, gives the result string.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.