Bash에서 4 자리 유니 코드 문자를 어떻게 에코합니까?


224

쉘 프롬프트 (특히 'SKULL AND CROSSBONES'(U + 2620))에 유니 코드 스컬과 크로스 본을 추가하고 싶지만, 에코 침을 뱉어내는 마법의 마법을 알아낼 수는 없습니다. 4 자리 유니 코드 문자 두 자리 숫자는 쉽습니다. 예를 들어 echo -e "\ x55",입니다.

아래의 답변 외에도 터미널은 출력이 예상 한대로 유니 코드를 지원해야한다는 점에 유의해야합니다. gnome-terminal은이 작업을 잘 수행하지만 반드시 기본적으로 켜져 있지는 않습니다.

macOS의 터미널 앱에서 환경 설정-> 인코딩으로 이동하여 유니 코드 (UTF-8)를 선택하십시오.


7
당신의 것을 참고 "2 개 자리 일의가 (에코에) 쉽게"는 코멘트에 값까지에 대해서만 유효하지 않습니다 "\x7F"합니다 (이는 UTF-8 로케일에서 bash태그가 당신이 제안) ... 패턴에 의해 표현 단일 바이트 된다 결코 범위 \x80-\xFF. 이 범위는 1 바이트 UTF-8 문자에서 유효하지 않습니다. 예를 들어, 유니 코드 코드 포인트 값 U+0080(예 \x80\xC2\x80
:)

4
printf "\\u007C\\u001C".
kenorb

NB : 나를 위해 gnome-terminal, echo -e '\ufc'심지어 UTF-8 문자 인코딩 설정과 더불어, ü를 생성하지 않습니다. 그러나 urxvt예를 printf "\\ub07C\\ub01C"들어 예상대로 인쇄 합니다 ( 또는 상자가 아님).
isomorphismes

@ Peter.O 왜 bash태그가 유용한 힌트입니까? CJK에서 다른 터미널이 공통적입니까?
동 형사상

1
@ Peter.O zsh, fish, scsh, elvish 등 ... 많은 다른 쉘이 있으며 각각은 유니 코드 문자를 처리 할 수 ​​있지만 원하지 않습니다. "bash"는이 질문이 일을 다르게하는 이상한 껍질에 관한 것이 아니라는 것을 분명히합니다.
masukomi

답변:


237

UTF-8에서는 실제로 6 자리 (또는 3 바이트)입니다.

$ printf '\xE2\x98\xA0'

콘솔에서 어떻게 인코딩되는지 확인하려면 hexdump를 사용하십시오.

$ printf  | hexdump
0000000 98e2 00a0                              
0000003

5
내 ☠ 대신 " "가 출력됩니다. 왜 그렇습니까?
trusktr

8
사실입니다. 내가 LANG=C대신 사용하고 있음을 발견했습니다 LANG=en_US.UTF-8. 이제 Gnome의 터미널이 심볼을 올바르게 표시합니다 ... 실제 터미널 (tty1-6)은 여전히 ​​그렇습니다.
trusktr

6
hexdump를 시도하는 사람들에게 :은로 0000000 f0 9f 8d ba번역됩니다 \xf0\x9f\x8d\xba. 에코 예 : echo -e "\xf0\x9f\x8d\xba".
Blaise

8
또한 이스케이프 시퀀스를 해석하지 않는 컨텍스트에서 사용하기 위해 캡처 서브 쉘을 사용 $'...'하지 않고 구문을 사용하여 인코딩 된 문자를 변수로 가져올 수 있습니다 $(...).skull=$'\xE2\x98\xA0'
Andrew Janke

7
hexdump에 대한 또 다른 것 : 내 컴퓨터에서 두 번째 명령은 출력을 출력 0000000 98e2 00a0합니다. 물론 0000000이것은 중요하지 않은 오프셋이지만 \xe2\x98\xa0기계가 리틀 엔디안 바이트 순서를 사용하기 때문에 변환 된 후의 바이트는로 변환됩니다 .
sigalor

98
% echo -e '\u2620'     # \u takes four hexadecimal digits

% echo -e '\U0001f602' # \U takes eight hexadecimal digits
😂

이것은 Zsh (버전 4.3을 확인했습니다)와 Bash 4.2 이상에서 작동합니다.


16
내가 할 때 \ u2620을 뱉어냅니다.
masukomi

나도. Juliano, 어떤 쉘을 사용하고 있습니까?
Joachim Sauer

2
죄송합니다. zsh를 사용하는 것을 잊었습니다.
Juliano

32
\ u에 대한 지원이 Bash 4.2에 추가되었습니다.
Lri

4
Mac OS 10.14.2, bash (GNU bash, 버전 3.2.57 (1)-릴리스 (x86_64-apple-darwin18))에서는 작동하지 않습니다. 그것은 단지 입력을 출력합니다-$ echo -e '\ u2620'<enter> 단순히 출력합니다 : \ u2620
Motti Shneor

68

텍스트 편집기에서 유니 코드 (아마 UTF-8로 인코딩 된)를 처리 할 수 ​​있으면 유니 코드 코드 포인트를 직접 입력 할 수 있습니다.

예를 들어 Vim 텍스트 편집기에서 삽입 모드를 시작하고 Ctrl+ V+ U를 누른 다음 코드 포인트 번호를 4 자리 16 진수 (필요한 경우 0이 포함 된 패드)로 누릅니다. Ctrl+ V+를 입력하십시오 U 2 6 2 0. 문서에 유니 코드 문자를 삽입하는 가장 쉬운 방법은 무엇입니까?를 참조하십시오.

Bash를 실행하는 터미널에서 CTRL+ SHIFT+ U를 입력하고 원하는 문자의 16 진 코드 포인트를 입력하십시오. 입력하는 동안 커서에 밑줄이 표시되어야합니다 u. 입력 한 숫자가 아닌 첫 번째 문자는 입력을 끝내고 문자를 렌더링합니다. 따라서 다음을 사용하여 Bash에서 U + 2620을 인쇄 할 수 있습니다.

echo CTRL+ SHIFT+U2620ENTERENTER

첫 번째 입력은 유니 코드 입력을 끝내고 두 번째 입력은 echo명령을 실행합니다 .

크레딧 : Ask Ubuntu SE


1
16 진 코드 포인트의 좋은 소스는 unicodelookup.com/#0x2620/1
RobM

1
ctrl-v와 u 사이에 점이있을 때 (RHEL 6.3의 7.2.411) 사용중인 vim 버전이 원하는대로 응답하지 않지만 해당 점을 생략하면 잘 작동합니다.
크리스 존슨

@ChrisJohnson : 지침에서 마침표를 제거했지만 키를 누르는 것이 아닙니다 (키보드 효과와 함께 나타나지 않았습니다). 혼란을 드려 죄송합니다.
RobM

5
주의 : 이것은 GTK + 환경에서 Gnome과 같이 Bash를 실행하는 경우에만 Bash를 실행하는 터미널에서 작동합니다 .
nr

1
하는 기능은 C-S-u 2 6 2 0터미널 에뮬레이터, X 입력 방식 (XIM), 또는 유사한의 기능입니다. AFAIK, 터미널 계층 SHIFTCTRL터미널 계층을 모두 보낼 수 없습니다 . 터미널은 X 서버와 같은 키심 및 키 코드가 아닌 문자 만 사용합니다 (또한 모든 의도와 목적을위한 7 비트 임). 이 세계 CTRL에서 4 개의 최상위 비트 (& 0b00001111)를 마스킹
-info

31

다음은 완전히 내부 Bash 구현이며, 포크는없고 무제한 크기의 유니 코드 문자입니다.

fast_chr() {
    local __octal
    local __char
    printf -v __octal '%03o' $1
    printf -v __char \\$__octal
    REPLY=$__char
}

function unichr {
    local c=$1    # Ordinal of char
    local l=0    # Byte ctr
    local o=63    # Ceiling
    local p=128    # Accum. bits
    local s=''    # Output string

    (( c < 0x80 )) && { fast_chr "$c"; echo -n "$REPLY"; return; }

    while (( c > o )); do
        fast_chr $(( t = 0x80 | c & 0x3f ))
        s="$REPLY$s"
        (( c >>= 6, l++, p += o+1, o>>=1 ))
    done

    fast_chr $(( t = p | c ))
    echo -n "$REPLY$s"
}

## test harness
for (( i=0x2500; i<0x2600; i++ )); do
    unichr $i
done

출력은 다음과 같습니다

─━│┃┄┅┆┇┈┉┊┋┌┍┎┏
┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟
┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯
┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿
╀╁╂╃╄╅╆╇╈╉╊╋╌╍╎╏
═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟
╠╡╢╣╤╥╦╧╨╩╪╫╬╭╮╯
╰╱╲╳╴╵╶╷╸╹╺╻╼╽╾╿
▀▁▂▃▄▅▆▇█▉▊▋▌▍▎▏
▐░▒▓▔▕▖▗▘▙▚▛▜▝▞▟
■□▢▣▤▥▦▧▨▩▪▫▬▭▮▯
▰▱▲△▴▵▶▷▸▹►▻▼▽▾▿
◀◁◂◃◄◅◆◇◈◉◊○◌◍◎●
◐◑◒◓◔◕◖◗◘◙◚◛◜◝◞◟
◠◡◢◣◤◥◦◧◨◩◪◫◬◭◮◯
◰◱◲◳◴◵◶◷◸◹◺◻◼◽◾◿

나는 round-about 메소드의 추론과 REPLY 변수의 구체적인 사용에 대해 매우 궁금합니다. 나는 당신이 bash 소스를 조사했거나 실행하거나 최적화 할 것을 가정한다고 가정한다.
nabin-info

14

쉘 스크립트에 "☠"을 넣으십시오. 올바른 로케일과 유니 코드 가능 콘솔에서는 잘 인쇄됩니다.

$ echo 

$

추악한 "해결 방법"은 UTF-8 시퀀스를 출력하는 것이지만 사용 된 인코딩에 따라 다릅니다.

$ echo -e '\xE2\x98\xA0'

$

13

UTF-8 문자를 3 바이트 형식으로 변환하는 빠른 한 줄짜리 :

var="$(echo -n '☠' | od -An -tx1)"; printf '\\x%s' ${var^^}; echo

5
위의 예제를 빨리 호출하지는 않습니다 (11 명령 및 매개 변수 포함) ... 또한 3 바이트 UTF-8 문자 만 처리합니다 (UTF-8 문자는 1, 2 또는 3 바이트 일 수 있음) ... 조금 더 짧고 1-3 ++++ 바이트에서 작동합니다. printf "\\\x%s" $(printf '☠'|xxd -p -c1 -u).... xxd 는 'vim-common'패키지의 일부로 제공됩니다
Peter.O

추신 : 방금 위의 hexdump / awk 예제가 바이트 쌍의 바이트 시퀀스를 소멸한다는 것을 알았습니다. 이것은 하지 않는 수정 UTF-8 덤프에 적용됩니다. UTF-16LE의 덤프이고 유니 코드 코드 포인트 를 출력하려는 경우 관련이 있지만 입력이 UTF-8이고 출력이 정확히 입력 (각 16 진수 앞의 \ x이므로 의미가 없음) -pair)
Peter.O

7
UTF-8 문자는 1-4 바이트 시퀀스 일 수 있습니다
cms

1
@ Peter.O의 의견을 바탕으로, 다음은 더 크고 꽤 편리하다는 것을 알았습니다.hexFromGlyph(){ if [ "$1" == "-n" ]; then outputSeparator=' '; shift; else outputSeparator='\n'; fi for glyph in "$@"; do printf "\\\x%s" $(printf "$glyph"|xxd -p -c1 -u); echo -n -e "$outputSeparator"; done } # usage: $ hexFromGlyph ☠ ✿ \xE2\x98\xA0 \xE2\x9C\xBF $ hexFromGlyph -n ☠ ✿ \xE2\x98\xA0 \xE2\x9C\xBF
StephaneAG

2
좋은 신 이시여 고려 : codepoints () { printf 'U+%04x\n' ${@/#/\'} ; } ; codepoints A R ☯ 🕉 z ... 즐기십시오
-info

8

나는 이것을 사용하고있다 :

$ echo -e '\u2620'

이것은 16 진수 표현을 검색하는 것보다 훨씬 쉽습니다 ... 쉘 스크립트에서 이것을 사용하고 있습니다. 그것은 gnome-term 및 urxvt AFAIK에서 작동합니다.


2
@masukomi brew를 사용하는 방법을 알고 있다면 최신 bash를 설치하고 사용할 수 있습니다. 업그레이드 된 bash를 사용할 때 위의 맥 터미널에서 정상적으로 작동합니다.
mcheema

예, 최신 버전의 bash에서는 괜찮습니다. Hower 프롬프트 문자열 (예 : $ PS1)은 에코 이스케이프 형식을 사용하지 않습니다
cms

6

프롬프트 확장으로 올바르게 디코딩하려면 코드 포인트를 8 진수로 인코딩해야 할 수 있습니다.

UTF-8로 인코딩 된 U + 2620은 E2 98 A0입니다.

배쉬에서는

export PS1="\342\230\240"

쉘 프롬프트를 두개골과 뼈로 만듭니다.


안녕하세요, "e0 b6 85"에 입력해야하는 코드는 무엇입니까? 어떻게 찾을 수 있습니까?
Udayantha Udy Warnasuriya

16 진 (밑수 16) 숫자 e0 b6 85를 8 진수 (밑수 8)로 변환하십시오. 계산기를 사용하는 것이 가장 쉬운 방법 일 것입니다
cms

e0 b6 85 hex is 340266205 8 진수
cms

고마워요! 그리고 BTW, 할 수 있습니다 findal이 페이지에서 진수 버전 : graphemica.com/%E2%9B%B5
Perlnika

6

bash에서 출력 할 유니 코드 문자를 인쇄하려면 \ x, \ u 또는 \ U를 사용하십시오 (첫 번째는 두 자리 16 진수, 두 번째는 4 자리 16 진수, 세 번째는 모든 길이)

echo -e '\U1f602'

변수 사용 $ '...'구문에 지정하고 싶습니다

x=$'\U1f602'
echo $x

5

Perl one-liner가 마음에 들지 않으면 :

$ perl -CS -E 'say "\x{2620}"'

-CS입력시 UTF-8 디코딩 및 출력시 UTF-8 인코딩을 활성화합니다. -E다음과 같은 현대적인 기능을 say사용 하여 다음 인수를 Perl로 평가합니다 . 마지막에 줄 바꿈을 원하지 않으면 print대신을 사용하십시오 say.


5

콘솔이 UTF-8 문자 (가장 최신 문자)를 허용하는 경우이 세 명령 중 하나가 콘솔에서 원하는 문자를 인쇄합니다 .

echo -e "SKULL AND CROSSBONES (U+2620) \U02620"
echo $'SKULL AND CROSSBONES (U+2620) \U02620'
printf "%b" "SKULL AND CROSSBONES (U+2620) \U02620\n"

SKULL AND CROSSBONES (U+2620) 

그런 다음 실제 글리프 (이미지, 문자)를 복사하여 (UTF-8 사용) 텍스트 편집기에 붙여 넣을 수 있습니다.

이러한 유니 코드 코드 포인트가 UTF-8로 인코딩되는 방법을 확인하려면 xxd를 사용하십시오 (od보다 훨씬 나은 16 진 뷰어).

echo $'(U+2620) \U02620' | xxd
0000000: 2855 2b32 3632 3029 20e2 98a0 0a         (U+2620) ....

That means that the UTF8 encoding is: e2 98 a0

또는 오류를 피하기 위해 HEX에서 : 0xE2 0x98 0xA0. 즉, 공간 (HEX 20)과 Line-Feed (Hex 0A) 사이의 값입니다.

숫자를 문자로 변환 하는 방법에 대해 자세히 알아 보려면 Greg Wiki (BashFAQ)에서 Bash의 ASCII 인코딩에 대한 기사를 참조하십시오!


re : "또는 헥사에서 오류를 피하기 위해 ..."나는 유니 코드 문자를 16 진 문자로 표현하는 이진 인코딩으로 변환하면 오류를 피하는 데 도움이된다고 생각 하지 않습니다. "bash"에서 유니 코드 표기법을 사용하면 오류를 피하는 것이 좋습니다. ---- 값이 ---- 16 진 값 HHHHHHHH (1-8 개의 16 진수) 인 유니 코드 (ISO / IEC 10646) 문자
Astara

4

printf내장은 (단지로 coreutils '등 printf)을 알고 \u4 자리 유니 코드 문자를 받아 이스케이프 시퀀스를 :

   \uHHHH Unicode (ISO/IEC 10646) character with hex value HHHH (4 digits)

Bash 4.2.37 (1)로 테스트 :

$ printf '\u2620\n'

printf는 또한 쉘 내장입니다. 아마도 기본 macOS bash (v3)를 사용하고있을 것입니다. 함께 시도 \printf독립 실행 파일을 사용하거나 업그레이드 배쉬와 시도
mcint

4

이 오래된 질문을 되살려 서 죄송합니다. 그러나 사용하는 경우 bash에도 일반 아스키 입력에서 유니 코드 코드 포인트를 만들 수있는 아주 쉬운 방법이 포크하지 않습니다 전혀은 :

unicode() { local -n a="$1"; local c; printf -vc '\\U%08x' "$2"; printf -va "$c"; }
unicodes() { local a c; for a; do printf -vc '\\U%08x' "$a"; printf "$c"; done; };

특정 코드 포인트를 정의하려면 다음과 같이 사용하십시오

unicode crossbones 0x2620
echo "$crossbones"

또는 첫 번째 65536 유니 코드 코드 포인트를 stdout에 덤프하려면 (내 컴퓨터에서 2 초 미만 걸립니다. 추가 공간은 쉘의 모노 스페이스 글꼴로 인해 특정 문자가 서로 흐르지 않도록하는 것입니다).

for a in {0..65535}; do unicodes "$a"; printf ' '; done

또는 매우 전형적인 부모님의 이야기를 들려줍니다 (유니 코드 2010이 필요합니다).

unicodes 0x1F6BC 32 43 32 0x1F62D 32 32 43 32 0x1F37C 32 61 32 0x263A 32 32 43 32 0x1F4A9 10

설명:

  • printf '\UXXXXXXXX' 모든 유니 코드 문자를 인쇄합니다
  • printf '\\U%08x' number\UXXXXXXXX16 진수로 변환 된 숫자로 인쇄 한 다음 printf실제로 유니 코드 문자를 인쇄 하기 위해 다른 것으로 공급됩니다.
  • printf 8 진수 (0oct), 16 진수 (0xHEX) 및 10 진수 (0 또는 1 ~ 9로 시작하는 숫자)를 숫자로 인식하므로 가장 적합한 표현을 선택할 수 있습니다
  • printf -v var ..포크없이printf 변수 의 출력을 수집합니다 (엄청나게 속도를 높입니다)
  • local variable 전역 네임 스페이스를 오염시키지 않아야합니까?
  • local -n var=other할당이 변경 되도록 별칭 var을로 other지정합니다 . 여기서 흥미로운 부분 중 하나 는 로컬 네임 스페이스의 일부이고 전역 네임 스페이스의 일부입니다. varothervarother
    • local또는 global네임 스페이스 와 같은 것이 없습니다 bash. 변수는 환경에 유지되며 항상 전역 적입니다. Local은 현재 값을 저장하고 함수가 다시 떠날 때 복원합니다. 함수 내에서 호출 된 다른 함수에는 local여전히 "로컬"값이 표시됩니다. 이것은 다른 언어에서 발견되는 모든 일반적인 범위 지정 규칙과 근본적으로 다른 개념입니다 (그리고 bash매우 강력하지만이를 모르는 프로그래머라면 오류가 발생할 수 있습니다).

글쎄-전혀 작동하지 않습니다. 함수를 사용하려고하면 방출됩니다 : 라인 6 : 로컬 : -n : 유효하지 않은 옵션 로컬 : 사용법 : 로컬 이름 [= 값] ... 최신 (10.14.2) MacOS 및 bash (GNU bash)를 사용하고 있습니다 , 버전 3.2.57 (1)-릴리스 (x86_64-apple-darwin18))
Motti Shneor

4

사용 가능한 모든 유니 코드 이모 지 목록은 다음과 같습니다.

https://en.wikipedia.org/wiki/Emoji#Unicode_blocks

예:

echo -e "\U1F304"
🌄

이 문자의 ASCII 값을 얻으려면 hexdump를 사용하십시오.

echo -e "🌄" | hexdump -C

00000000  f0 9f 8c 84 0a                                    |.....|
00000005

그런 다음 16 진수 형식의 정보를 사용하십시오.

echo -e "\xF0\x9F\x8C\x84\x0A"
🌄

\ U <hex> 문자열을 반향하는 것은 OSX에서 작동하지 않으며 따옴표 안에있는 것을 정확하게 출력합니다.
masukomi


2

Python2 / 3 one-liner를 사용하면 쉽습니다.

$ python -c 'print u"\u2620"'    # python2
$ python3 -c 'print(u"\u2620")'  # python3

결과 :


2

배쉬에서 :

UnicodePointToUtf8()
{
    local x="$1"               # ok if '0x2620'
    x=${x/\\u/0x}              # '\u2620' -> '0x2620'
    x=${x/U+/0x}; x=${x/u+/0x} # 'U-2620' -> '0x2620'
    x=$((x)) # from hex to decimal
    local y=$x n=0
    [ $x -ge 0 ] || return 1
    while [ $y -gt 0 ]; do y=$((y>>1)); n=$((n+1)); done
    if [ $n -le 7 ]; then       # 7
        y=$x
    elif [ $n -le 11 ]; then    # 5+6
        y=" $(( ((x>> 6)&0x1F)+0xC0 )) \
            $(( (x&0x3F)+0x80 ))" 
    elif [ $n -le 16 ]; then    # 4+6+6
        y=" $(( ((x>>12)&0x0F)+0xE0 )) \
            $(( ((x>> 6)&0x3F)+0x80 )) \
            $(( (x&0x3F)+0x80 ))"
    else                        # 3+6+6+6
        y=" $(( ((x>>18)&0x07)+0xF0 )) \
            $(( ((x>>12)&0x3F)+0x80 )) \
            $(( ((x>> 6)&0x3F)+0x80 )) \
            $(( (x&0x3F)+0x80 ))"
    fi
    printf -v y '\\x%x' $y
    echo -n -e $y
}

# test
for (( i=0x2500; i<0x2600; i++ )); do
    UnicodePointToUtf8 $i
    [ "$(( i+1 & 0x1f ))" != 0 ] || echo ""
done
x='U+2620'
echo "$x -> $(UnicodePointToUtf8 $x)"

산출:

─━│┃┄┅┆┇┈┉┊┋┌┍┎┏┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟
┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿
╀╁╂╃╄╅╆╇╈╉╊╋╌╍╎╏═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟
╠╡╢╣╤╥╦╧╨╩╪╫╬╭╮╯╰╱╲╳╴╵╶╷╸╹╺╻╼╽╾╿
▀▁▂▃▄▅▆▇█▉▊▋▌▍▎▏▐░▒▓▔▕▖▗▘▙▚▛▜▝▞▟
■□▢▣▤▥▦▧▨▩▪▫▬▭▮▯▰▱▲△▴▵▶▷▸▹►▻▼▽▾▿
◀◁◂◃◄◅◆◇◈◉◊○◌◍◎●◐◑◒◓◔◕◖◗◘◙◚◛◜◝◞◟
◠◡◢◣◤◥◦◧◨◩◪◫◬◭◮◯◰◱◲◳◴◵◶◷◸◹◺◻◼◽◾◿
U+2620 -> 

0

유니 코드 문자의 16 진수 값을 알고있는 경우

H="2620"
printf "%b" "\u$H"

유니 코드 문자의 10 진수 값을 알고있는 경우

declare -i U=2*4096+6*256+2*16
printf -vH "%x" $U              # convert to hex
printf "%b" "\u$H"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.