印刷できない文字を含む変数を印刷するには?

印刷できない文字を含む変数を印刷するには?

$IFS印刷できない文字(改行文字など)を含めることができる変数の値を表示したいと思います。

これを行うには、次のコマンドを使用します。

echo -n "$IFS" | hexdump -C

これは私にとってうまくいきます。

しかし、このコマンドを使用するのに問題がありますか?たとえば、echo印刷できない文字を印刷する前に他の文字に置き換えますか?stdoutそれとも同様の問題がありますか?

答え1

文字列を視覚的に表現するいくつかの異なる方法:

POSIX

$ 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$

(追加のコンテンツが\n必要です。そうしないと、sed最後の行が改行文字で終わらない限り動作は指定されません。)POSIXには、私のzshのようにNULはありませんsh。入力に ​​NUL が含まれている場合、動作は指定されません。$IFSsed

シェル組み込み関数

  • 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]'
    

    ただし、後者(鋭角アクセントと幅0の空白文字を結合するためにUnicodeを使用する場合)の場合、zsh / mkshは役に立ちません(にもかかわらずLC_ALL=C typeset -p amksh -o utf8-modebash端末に送信されると、出力は通常明確ではありません。

  • printf %qprintfGNUprintfの組み込み機能を使用しksh93て、次の操作を行いますzshbash

    $ 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'
    ''
    
  • q、、qqのパラメータ拡張フラグqqqqqqqzsh

    さまざまな種類の参照については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'
    

    次への参照のみを使用してくださいqq+必要はい(Unicodeに関する警告はまだ存在しますが)。

さまざまな非標準コマンド:

  • hex-dumper:hexdump、、、...供給する出力(またはksh / zshを使用するか...hdを使用)。xxdprintf %s "$var"print -rn -- "$var"echo -nE - "$var"zsh

  • cat -vteまたはcat -A

  • uconv -x hex文字のUnicodeコードポイント(エンコードされたバイトの16進値ではない)の場合は、UTF-8でのみ機能します(入力は前処理できますが、iconv -t utf-8ロケールエンコーディングで有効なテキストである場合のみ)。

  • uconv -x name役割名の場合

  • recode ..dump。 16進数と名前ですが、少数のUnicode文字を理解しています(最新バージョンのUnicodeに更新されていません)。ただし、UTF-8以外のロケールでは機能します。

答え2

特に場合はIFS必ず引用したいか、そうでなければ役に立たなくなります。もうやったので問題ありません。

の場合はecho場合によって異なります。一部のバージョンはechoデフォルトでバックスラッシュエスケープを処理しますが、一部はそうではありません。 Bashはそうではありませんが、zshは次のことを行います。

$ bash -c 'echo "foo\nbar"'
foo\nbar
$ zsh -c 'echo "foo\nbar"'
foo
bar

使用する方が良いですprintfprintf "%s" "$IFS" | hexdump -C

また見なさい:なぜprintfがechoより優れているのですか?

printf "%q" "$IFS"Bashとzshでも動作します。

\0これは、BashがNULバイト()をまったく処理できないのに対し、zshは処理できることを除いて良い状態を維持する必要があります。大きな打撃:

$ var=$'foo\0bar'
$ printf "%q\n" "$var"
foo

ジシュ語:

$ var=$'foo\0bar'
$ printf "%q\n" "$var"
foo$'\0'bar

答え3

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    ...............

printf移植性は優れてechoいますが、私のシステムとシェルでは出力はまったく同じです。

printf %s "$var"

答え4

私はQBashのパラメータ変換演算子が好きです:

echo "${IFS@Q}"

出力:

$' \t\n'

この$'string'参照はANSI-Cの引用

このQ演算子は、SSHを介してコマンドに引数を渡すためにも使用できます。

f='filename with space'
ssh "$host" "ls -l ${f@Q}"

これパラメータ拡張セクションにはすべての演算子のリストが含まれています。このA演算子も便利です。

a=(array with 'various elements')
echo "${a[@]@A}"

出力:

declare -a a=([0]="array" [1]="with" [2]="various elements")

関連情報