我发现的方法还通过影响换行符来进一步破坏线路。
例如...
$ message="First Line\nSecond Line";
$ echo "${message^^}"
FIRST LINE\NSECOND LINE
是否有一种优雅的方法将字符串转换为大写,但保留转义字符,以获得以下输出?
FIRST LINE\nSECOND LINE
我可以做一些复杂的事情,比如将“\n”更改为 0001 或类似的操作,应用转换,然后将 0001 返回到“\n”。但也许有更好的方法。
答案1
用zsh
而不是bash
:
$ message="First Line\nSecond Line"
$ set -o extendedglob
$ print -r -- ${message//(#b)((\\?)|(?))/$match[2]$match[3]:u}
FIRST LINE\nSECOND LINE
在bash
(或任何 shell)中,使用 的 GNU 实现sed
,您可以执行相同的操作:
$ printf '%s\n' "$message" | sed -E 's/(\\.)|(.)/\1\u\2/g'
FIRST LINE\nSECOND LINE
一些可能更有效的变体,因为它们最大限度地减少了替换数量:
zsh
print -r -- ${message//(#b)((\\?)|([^\\]##))/$match[2]$match[3]:u}
或者
print -r -- ${message//(#b)((\\?)#)([^\\]##)/$match[1]$match[3]:u}
他们的 GNU
sed
翻译:printf '%s\n' "$message" | sed -E 's/(\\.)|([^\\]+)/\1\U\2/g'
或者
printf '%s\n' "$message" | sed -E 's/((\\.)*)([^\\]+)/\1\U\3/g'
请注意,它们会将(Meta-x,例如s\Mx
支持的转义序列,并扩展为 0xf8 字节 ('x' + 0x80))转换为(0xd8)。它们也转换为或到或到,但这应该不是问题,因为它们扩展为相同的。zsh
print
\MX
\x7a
\x7A
\u007a
\u007A
\Cx
\CX
答案2
我很想将转义序列解释为文字字符:
message="First Line\nSecond Line"
declare -u Message # uppercase on assignment
printf -v Message -- "${message//%/%%}" # assign
declare -p Message # inspect
结果
declare -u msg="FIRST LINE
SECOND LINE"
答案3
echo "$message" | sed -e 's/^[[:lower:]]/\u&/' -e 's/\([^\]\)\([[:lower:]]\)/\1\u\2/g' \
-e 's/\([^\]\)\([[:lower:]]\)/\1\u\2/g'
-e 's/^[[:lower:]]/\u&/'
如果字符串中的第一个字符(或者更一般地说,一行中的第一个字符)是小写字母,请将其大写。因为一行中的第一个字符无法转义。呃。这是理所当然的。-e 's/\([^\]\)\([[:lower:]]\)/\1\u\2/g'
一次查看该行两个字符。如果小写字母前面不是反斜杠,则保留前面的字符,并将小写字母大写。您可能认为这足以处理整条线。不幸的是,由于它一次处理该行两个字符,所以它只获取每隔一个的字母:
$ echo "first line\nsecond line" | sed -e 's/\([^\]\)\([[:lower:]]\)/\1\u\2/g' fIrSt LiNe\nSeCoNd LiNe
所以,
-e 's/\([^\]\)\([[:lower:]]\)/\1\u\2/g'
第二次做同样的事情。这将拾取第一次传递时跳过的字母。
替代版本:
echo "$message" | sed -e 's/^[[:lower:]]/\u&/' \
-e ': loop; s/\([^\]\)\([[:lower:]]\)/\1\u\2/g; t loop'
与第一个版本基本相同,但不是重复第二个版本s
命令,它用循环迭代它。
不幸的是,这对于双反斜杠将无法正常工作: 即使 应该大写,也会foo\\bar
变成,因为是转义的反斜杠,因此不应导致被转义。FOO\\bAR
b
\\
b
答案4
该变量可以逐行迭代。然后再次连接输出。
重击:
$ 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