use*_*971 10 shell character-encoding special-characters variable
我想显示$IFS
变量的值,它可能包含不可打印的字符(例如:换行符)。
我使用以下命令来做到这一点:
echo -n "$IFS" | hexdump -C
Run Code Online (Sandbox Code Playgroud)
在我的情况下效果很好。
但是使用这个命令有什么问题吗?例如,在echo
将某些无法打印的字符打印到它的stdout
.
尤其是对于IFS
,您绝对想引用它,否则它就会变成空。你已经这样做了,所以没问题。
至于echo
,这取决于外壳。echo
默认情况下,某些版本的处理反斜杠转义符,有些则不处理。Bash 没有,zsh 有:
$ bash -c 'echo "foo\nbar"'
foo\nbar
$ zsh -c 'echo "foo\nbar"'
foo
bar
Run Code Online (Sandbox Code Playgroud)
最好printf
改用:printf "%s" "$IFS" | hexdump -C
。
另请参阅:为什么 printf 比 echo 好?
printf "%q" "$IFS"
也适用于 Bash 和 zsh。
这应该会让你保持良好状态,除了 Bash 根本无法处理 NUL 字节 ( \0
),而 zsh 可以。重击:
$ var=$'foo\0bar'
$ printf "%q\n" "$var"
foo
Run Code Online (Sandbox Code Playgroud)
zsh:
$ var=$'foo\0bar'
$ printf "%q\n" "$var"
foo$'\0'bar
Run Code Online (Sandbox Code Playgroud)
给出字符串的视觉表示的一些不同方法:
$ printf %s "$IFS" | od -vtc -to1
0000000 \t \n \0
040 011 012 000
0000004
$ printf '%s\n' "$IFS" | LC_ALL=C sed -n l
\t$
\000$
Run Code Online (Sandbox Code Playgroud)
(额外的内容\n
是必要的,否则sed
如果最后一行没有以换行符结尾,则行为是未指定的)。POSIXsh
不会$IFS
像我的 zsh 那样包含 NUL 。sed
如果输入包含 NUL ,则的行为未指定。
typeset -p
(ksh, zsh, bash, yash) 可能会为某些字符串提供明确的输出。
$ ksh93 -c 'typeset -p IFS'
IFS=$' \t\n'
$ zsh -c 'typeset -p IFS'
typeset IFS=$' \t\n\C-@'
$ mksh -c 'typeset -p IFS'
typeset IFS=$' \t\n'
$ a=$'\u00e9e\u301\u200b' ksh -c 'typeset -p a'
typeset -x a=$'\u[e9]e\u[301]\u[200b]'
Run Code Online (Sandbox Code Playgroud)
但是对于后一个(使用 Unicode 结合重音符号和零宽度空格字符), zsh/mksh 没有帮助(即使LC_ALL=C typeset -p a
使用mksh -o utf8-mode
)。bash
的输出在发送到终端时通常不是明确的。
printf %q
使用 GNUprintf
和printf
内置的ksh93
,zsh
和bash
:
$ a=$'\u00e9e\u301\u200b' bash -c 'printf "%q\n" "$IFS" "$a" ""'
$' \t\n'
éé?
''
$ a=$'\u00e9e\u301\u200b' ksh -c 'printf "%q\n" "$IFS" "$a" ""'
$' \t\n'
$'\u[e9]e\u[301]\u[200b]'
''
\ $'\t'$'\n'$'\0'
éé?
''
$ a=$'\u00e9e\u301\u200b' sh -c '/usr/bin/printf "%q\n" "$IFS" "$a" ""'
' '$'\t\n'
éé?
''
$ a=$'\u00e9e\u301\u200b' zsh -c 'LC_ALL=C printf "%q\n" "$IFS" "$a" ""'
\ $'\t'$'\n'$'\0'
$'\303'$'\251'e$'\314'$'\201'$'\342'$'\200'$'\213'
''
$ a=$'\u00e9e\u301\u200b' bash -c 'LC_ALL=C printf "%q\n" "$IFS" "$a" ""'
$' \t\n'
$'\303\251e\314\201\342\200\213'
''
Run Code Online (Sandbox Code Playgroud)q
, qq
, qqq
, 中的qqqq
参数扩展标志zsh
。
对于各种类型的引用,qqqq
其中之一是$'...'
:
$ a=$'\u00e9e\u301\u200b' zsh -c 'print -r -- ${(qqqq)a}'
$'éé?'
$ a=$'\u00e9e\u301\u200b' zsh -c '(){local LC_ALL=C; print -r -- ${(qqqq)a}}'
$'\303\251e\314\201\342\200\213'
Run Code Online (Sandbox Code Playgroud)
还有q
and q+
that 只对需要它的东西使用引用(尽管对于那些 unicode 仍然有警告)。
hex-dumper: hexdump
, hd
, xxd
... 你想给他们输出printf %s "$var"
(或print -rn -- "$var"
用 ksh/zsh,或echo -nE - "$var"
用zsh
...)。
cat -vte
或者 cat -A
uconv -x hex
对于字符的 unicode 代码点(与编码字节的十六进制值相反),仅适用于 UTF-8(iconv -t utf-8
尽管只要它是语言环境编码中的有效文本,就可以对输入进行预处理)
uconv -x name
对于角色名称
recode ..dump
. 十六进制和名称,但知道较少的 Unicode 字符(未使用较新版本的 Unicode 进行更新)。虽然在非 UTF-8 语言环境中工作。
bash 中唯一不起作用的字符是 null。
$ var="$(perl -wE 'print map chr, 0 .. 255')"
$ echo -n "$var" | xxd
0000000: 0102 0304 0506 0708 090a 0b0c 0d0e 0f10 ................
0000010: 1112 1314 1516 1718 191a 1b1c 1d1e 1f20 ...............
0000020: 2122 2324 2526 2728 292a 2b2c 2d2e 2f30 !"#$%&'()*+,-./0
0000030: 3132 3334 3536 3738 393a 3b3c 3d3e 3f40 123456789:;<=>?@
0000040: 4142 4344 4546 4748 494a 4b4c 4d4e 4f50 ABCDEFGHIJKLMNOP
0000050: 5152 5354 5556 5758 595a 5b5c 5d5e 5f60 QRSTUVWXYZ[\]^_`
0000060: 6162 6364 6566 6768 696a 6b6c 6d6e 6f70 abcdefghijklmnop
0000070: 7172 7374 7576 7778 797a 7b7c 7d7e 7f80 qrstuvwxyz{|}~..
0000080: 8182 8384 8586 8788 898a 8b8c 8d8e 8f90 ................
0000090: 9192 9394 9596 9798 999a 9b9c 9d9e 9fa0 ................
00000a0: a1a2 a3a4 a5a6 a7a8 a9aa abac adae afb0 ................
00000b0: b1b2 b3b4 b5b6 b7b8 b9ba bbbc bdbe bfc0 ................
00000c0: c1c2 c3c4 c5c6 c7c8 c9ca cbcc cdce cfd0 ................
00000d0: d1d2 d3d4 d5d6 d7d8 d9da dbdc ddde dfe0 ................
00000e0: e1e2 e3e4 e5e6 e7e8 e9ea ebec edee eff0 ................
00000f0: f1f2 f3f4 f5f6 f7f8 f9fa fbfc fdfe ff ...............
Run Code Online (Sandbox Code Playgroud)
printf
那么更便携echo
,但对于我的系统和 shell (bash),它们的输出是完全相同的。
printf %s "$var"
Run Code Online (Sandbox Code Playgroud)