이스케이프 문자를 제외하고 대문자로 변환

이스케이프 문자를 제외하고 대문자로 변환

내가 찾은 방법은 줄 바꿈에 영향을 주어 줄을 더 나눕니다.
예를 들어...

$ 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

(또는 해당 문제에 대한 모든 쉘) 에서 bashGNU 구현을 사용하면 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'
    

\Mx(s에서 지원하고 0xf8 바이트('x' + 0x80)로 확장된 이스케이프 시퀀스와 같은 Meta-x)를 (0xd8)로 변환합니다 . 그들은 또한 or 로 변환하지만 동일하게 확장되므로 문제가 되지 않습니다.zshprint\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\\bARb\\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

관련 정보