4

The methods I found break things further down the line by also affecting linebreaks.
For example...

$ message="First Line\nSecond Line"; 
$ echo "${message^^}"
FIRST LINE\NSECOND LINE

Is there an elegant way to convert a string to uppercase, but leaving escaped characters alone, to get the following output instead?

FIRST LINE\nSECOND LINE

I could just do something convoluted like changing "\n" to 0001 or something along those lines, apply the conversion and then return 0001 to "\n". But maybe there is a better way.

4 Answers 4

4

With zsh instead of bash:

$ message="First Line\nSecond Line"
$ set -o extendedglob
$ print -r -- ${message//(#b)((\\?)|(?))/$match[2]$match[3]:u}
FIRST LINE\nSECOND LINE

In bash (or any shell) and with the GNU implementation of sed, you can do the same with:

$ printf '%s\n' "$message" | sed -E 's/(\\.)|(.)/\1\u\2/g'
FIRST LINE\nSECOND LINE

Some potentially more efficient variants as they minimise the number of substitutions:

  • zsh

    print -r -- ${message//(#b)((\\?)|([^\\]##))/$match[2]$match[3]:u}
    

    or

    print -r -- ${message//(#b)((\\?)#)([^\\]##)/$match[1]$match[3]:u}
    
  • their GNU sed translations:

    printf '%s\n' "$message" | sed -E 's/(\\.)|([^\\]+)/\1\U\2/g'
    

    or

    printf '%s\n' "$message" | sed -E 's/((\\.)*)([^\\]+)/\1\U\3/g'
    

Beware they convert \Mx (Meta-x, an escape sequence supported by zsh's print for instance and that expands to the 0xf8 byte ('x' + 0x80)) to \MX (0xd8). They also convert \x7a to \x7A or \u007a to \u007A or \Cx to \CX but that shouldn't be a problem as those expand to the same.

2

I'd be tempted to interpret the escape sequences into literal characters:

message="First Line\nSecond Line"
declare -u Message                       # uppercase on assignment
printf -v Message -- "${message//%/%%}"  # assign
declare -p Message                       # inspect

result

declare -u msg="FIRST LINE
SECOND LINE"
4
  • 3
    Beware that with message='\141' for instance, you'd get declare -u Message="A" instead of declare -u Message="a" 2 days ago
  • Note that any \ will ve doubled \\.
    – IsaaC
    2 days ago
  • 1
    Not giving printf a format causes the change of % that you want to avoid by duplicating every %. However, a printf -v Message '%b' -- "${message}" will interpret back-slashed characters exactly as echo -e without changing the %s.
    – IsaaC
    2 days ago
  • Please read: unix.stackexchange.com/q/700508/232326
    – IsaaC
    7 hours ago
0
echo "First Line\nSecond Line"|sed -e 's/.*/\U&/g' -e 's/\\./\L&/g'

output

FIRST LINE\nSECOND LINE
1
  • 2
    That changes \U0001F9DA (which would expand to 🧚) to \u0001F9DA which would expand to ^AF9DA though. yesterday
0

The variable can be iterated line by line. Then concatenate the output again.

bash:

$ message="First Line\nSecond Line";
$ message=$(echo -e ${message} |while read -r line; do echo -n "${line^^}\n" ; done) && message=${message%??}
$ echo ${message} 
FIRST LINE\nSECOND LINE
3

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.