web-dev-qa-db-ja.com

ヒアドキュメントでヌル文字をエスケープする方法(bashおよび/またはダッシュ)

やりたいshuf --zero-terminatedヒアドキュメントを含む複数行の文字列。

4
illiterate

Bashとdashのヒアドキュメントはこれをサポートしていません。変数にnullを格納することはできません。nullはコマンド置換から削除され、文字どおりに書き込むことはできません。また、ヒアドキュメント内でANSI-Cクォートを使用することはできません。どちらのシェルもnullに対応しておらず、一般的に(Cスタイルの)文字列ターミネーターとして扱われます。

いくつかのオプションがあります: 実際のファイルを使用 、zshを使用、プロセス置換を使用、または標準入力を使用します。


あなたはできますは、zshで必要なことを正確に実行できます。

zsh% null=$(printf '\x00')
zsh% hexdump -C <<EOT
heredoc> a${null}b${null}
heredoc> EOT
00000000  61 00 62 00 0a                                    |a.b..|
00000005

ただし、ヒアドキュメントには暗黙の終了改行があり、これは望ましくない場合があります(最後のnullの後のshufの追加フィールドになります)。


Bashの場合は、ヒアドキュメントとほぼ同等の プロセス置換printfまたはecho -eと組み合わせて使用​​して、インラインでnullを作成できます。

bash$ hexdump -C < <(
printf 'item 1\x00item\n2\x00'
)
00000000  69 74 65 6d 20 31 00 69  74 65 6d 0a 32 00        |item 1.item.2.|
0000000e

これは、ヒアドキュメントと完全に同等であるとは限りません。これらは、シェルによって実際にファイルに密かに入れられることが多いためです(特にシーク可能性が重要です)。

おそらく改行の終了を抑制したいので、そこでコマンド内でヒアドキュメントを内部的に使用することさえできません-出力をきめ細かく制御するために安全であればprintf/echo -neでなければなりません。


ダッシュでプロセス置換を行うことはできませんが、どのシェルでも、サブシェルから標準入力をパイプすることができます。

dash$ (
printf 'item 1\x00'
printf 'item\n2\x00'
) | hexdump -C
00000000  69 74 65 6d 20 31 00 69  74 65 6d 0a 32 00        |item 1.item.2.|
0000000e

shufはデフォルトで標準入力から読み取ってくれるので、私が理解しているように、具体的なユースケースで機能するはずです。より複雑なコマンドがある場合は、パイプラインの右側にいると、スコープ付けによって混乱する要素が発生する可能性があります。


最後に、printfを使用して実際のファイルにデータを書き込み、ヒアドキュメントの代わりにそれを使用できます。そのオプションは 他の答え でカバーされています。後でファイルを確実にクリーンアップする必要があります。ライブのセキュリティ上の懸念がある場合は、安全なファイル名を作成するために mktemp などを使用することもできます。

8
Michael Homer

皆さん、ありがとうございました。私はあなた全員に基づいて1つの回答ベースを投稿させてください。

このスクリプトは、bashとdashでうまく機能します。実際のファイルや bashでのプロセス置換 は必要ありません。エンティティのエスケープ問題を心配する必要がない場合でも、余分な低速の外部プログラム呼び出しは必要ありません。 %s in C printfただし、シェル自体の文字列エスケープには注意が必要です

#!/bin/sh
printf '%s\0' "[tag1]
key1=value1
key2=value2
[/tag1]
" "[tag2]
key3=value3
key4=value4
[/tag2]
" | shuf --zero-terminated
#also see man printf(1)

shuf のみ(一般的なヒアドキュメントの代替を意図していない):

shuf --echo "[tag1]
key1=value1
key2=value2
[/tag1]" "[tag2]
key3=value3
key4=value4
[/tag2]"
6
illiterate

ヒアドキュメントでやりたいことができるとは思いません。ただし、次の例に示すように、echoを使用するのは簡単です。

$ cat demo
#!/bin/bash

echo -ne "one\0" > outfile
echo -ne "two\0" >> outfile
echo -ne "three\0" >> outfile

$ ./demo
$ od -a outfile
0000000   o   n   e nul   t   w   o nul   t   h   r   e   e nul
0000016
$ 
3
fpmurphy