Nullおよびエスケープ文字の使用/読み取り/書き込み

Nullおよびエスケープ文字の使用/読み取り/書き込み

'/'私は2文字のsum以外にLinuxのファイル名に制限がないことを知っています'\0''/'ディレクトリ区切り記号なので禁止されていることを知っていますが、他に理由がありますか?

また私のターミナルで\0。だから私は知りたいヌル文字を書く正しい方法明らかに、nullを含むファイル名を許可しないでください。

mkdir '\0' という名前のファイルを生成します\0

もう一つ質問があります。ファイル名に含めるには$バックスラッシュを使用できます。

mkdir \$myfileという名前のファイルを生成します $myfile

ただし、ドル記号を一重引用符と二重引用符で囲んでも、これを行うことができます。

mkdir \$myfile同じ、同じ、同じ、mkdir '$'myfile同じmkdir "$"myfilemkdir '$myfile'mkdir "$myfile"

だから私の質問は、一重引用符と二重引用符は、バックスラッシュ文字をエスケープする代わりに使用できますか?

$、(スペース)とバックスラッシュに加えて、bashでエスケープする必要がある他の文字は何ですか?

答え1

ヌル文字の印刷

$'\0'最近の多くのシェルでは、ドル一重引用符形式、16進形式\x00、Unicode形式、または8進形式を使用して\u0000NULL文字を作成できます。キーは、コマンドがバックスラッシュエスケープ文字を処理する方法を知る必要があることです。たとえば、通常はオプションを追加する必要がある場合です。\U00000000'\0'echo-eprintf%b

動作していることを確認しましょう。

$ echo -ne '\0'
$

だから何も生成されませんecho -ne ''

$ printf '%b' '\0'
$

いくつかの文字を追加してみましょう(printf '%b'もっと強力ですが、同様の効果があるので、今から使い続けますecho -ne)。

$ printf '%b' a'\0'b
ab

2文字だけが印刷されます。無効行く?

$ printf '%b' a'\0'b | wc -c
3

比較してみましょうa''b

$ printf '%b' a''b | wc -c
2

最後に、ファイルを生成する前に実際にnull文字を印刷したことを確認するために、印刷された値をエラーを発生させるコマンドに渡しましょう。例xargs:

$ printf '%b' a'\0'b | xargs echo
xargs: Warning: a NUL character occurred in the input.  It cannot be 
passed through in the argument list.  Did you mean to use the --null option?
a

a最後に印刷する方法を確認してください。もちろんxargs -0うまくいきます。

$ printf '%b' a'\0'b | xargs -0 echo
a b

nullを使用してファイルを生成しますか?

それでは、null文字を含むファイルを作成しましょう。

$ touch $'\0'
touch: cannot touch ‘’: No such file or directory
$ mkdir $'\0'
mkdir: cannot create directory ‘’: No such file or directory

# let's try another approach - using printf in command substitution:
$ touch "$(printf '%b' '\0')"
touch: cannot touch ‘’: No such file or directory
$ mkdir "$(printf '%b' '\0')"
mkdir: cannot create directory ‘’: No such file or directory

結果は と全く同じですtouch ''無効一斉に無視されました。コマンドの代わりに二重引用符をスキップするとどうなりますか?

$ touch $(printf '%b' '\0')
touch: missing file operand
Try 'touch --help' for more information.
$ mkdir $(printf '%b' '\0')
mkdir: missing operand
Try 'mkdir --help' for more information.

これは、パラメータがまったくないtouch場合と同じです。mkdirもう一つの結果は、nullをテキストで囲む場合です。

$ touch "$(printf '%b' a'\0'b)"
$ ls
a   # in zsh
ab  # in bash

標準出力にリダイレクトすることもできますが、$'\0'取得するのはすべて他の種類のエラーだけです。

答え2

一重引用符/二重引用符とバックスラッシュ:一重引用符とバックスラッシュの引用機能は同じです。スペース、タブ、改行()[]*$><?|{}~&;"`^!#、その他の忘れた文字を含む長い文字列を引用するには、単一引用符を使用する方がはるかに便利です。ただし、バックスラッシュを使用すると、まったく同じ結果が得られます(`...`ただし、バックスラッシュ()内のバックスラッシュのオーバーロードに注意してください)。

ただし、二重引用符は一意です。 $二重引用符内では拡張しますが、一重引用符内では拡張しないでください。 "$foo"はfooを拡張しますが、トークン化とグローバル拡張による拡張結果を保護します。

http://mywiki.wooledge.org/BashFAQ始めるのに良い場所かもしれません。 Bashのマニュアルは、説明するすべての機能を使用する方法、個別に動作する方法を説明するのに多くの時間を費やすことはありません。


文字通りゼロバイトを含む文字列をコマンドライン引数やシステムコールに渡すことは不可能です。アプリケーションバイナリインタフェース(ABI)は、コマンドライン引数やシステムコールのファイル/パス引数を含むすべてのもの(バイナリデータを除く)を処理するためにC文字列を使用して、プロセスとカーネル間でデータが渡される方法を正確に指定します。します。 C文字列は、文字列の末尾がゼロバイトで表される文字の配列です。文字列の終わりではないことを示すためにゼロバイトを「エスケープ」する方法はありません。

同様の操作を試みると、引数リストは次のように処理されますtouch $'foo\0bar'touch

argv[0] = "/bin/touch";
argv[1] = "foo";

メモリでは、argv[1] = "foo\0bar\0"最初の項目は\0文字列の終わりを示します。実際、 "foo\0bar\0" は新しいプロセスの argv に到達しません。exevce(2)実行中のシステムコールのargv配列からは取得されませんtouch

ヌルバイトの文字配列/文字列を含むCまたはPerlプログラムを作成しても、それをシステムコールに渡すと、open(2)カーネルは文字列を同じに解釈します。read(2)などの任意のデータを処理する必要があるシステムコールは、長さ引数とバッファへwrite(2)のポインタを使用します。


bashを使用すると、nullバイトで何もできません。 jimmijが指摘したように、文字列リテラルを作成するbash構文はエスケープシーケンスを使用して処理することですが、文字列リテラルの内部に書き込むの$'string'\0bashの文字列終端として機能します。私はこれがbashが内部的に文字列を明示的な長さではなくC文字列として格納することを意味すると思います。

str=$'foo\0bar'
echo "${#str}"   # 3, showing that bash isn't even storing it in a variable.
echo "$str" | wc -c   # 4. wouldn't work even if ${#str} did: echo's cmdline would eat it
wc -c <<< $'foo\0bar'   # 4 (includes a newline)

したがって、この構文を使用すると、nullバイトをどこにでも送信できません。私たちは何かを使うべきですtr


しかしbashは。を含む。変換printfのバックスラッシュエスケープを処理し、既にその型文字列でこれらのエスケープを処理します。\0%b\0printf

  • printf '\0'0バイトを印刷します。hexdump -C確認するには入力してください。
  • printf '%s\0%s' foo bar | hexdump -Cstdoutに書き込みますfoo.bar(ここで.はNULバイトです)。一重引用符や二重引用符の中の内容はそれ\0自体では拡張されません。$'\0'引用符でのみ拡張できます。今後printfを使用すると、ターミネーターとして機能します。
  • printf '%b' 'foo\0bar'同じことを行いますが、より複雑です。

答え3

ご存知のように、$varこれは説明変数につながります。さまざまなオプションはさまざまな理由で機能します。

  • escape( \$var): 次の文字をシェル機能文字として解釈しません。ただし、場合によっては特別な意味が与えられます(たとえば、場合によって\nは改行に使用されます)。
  • 一重引用符('$var'):一重引用符内のすべての内容は、厳密にはその中に含まれる文字列です。
  • $()分離"$"var:シングルは$解釈されず、二重引用符で囲むと部分から分離され、var解釈は発生しません。
  • 二重引用符("$var"):実際に変数を解釈できるようにしますvarmkdir "$var"動作せず、他の変数と同じではありません!もう一度確認してください!ただし、引用符に含まれるすべての項目は単一の文字列として扱われます。名前にスペースを含むファイルの作成など、ファイル名に特殊文字が含まれている場合に特に便利です。touch "a b"->a b単一ファイルの作成/更新、touch a b-> 2つのaファイルの作成/更新b

> >> < << <<<他の特殊演算子には、リダイレクトと「heres」、プロセス演算子、ブール演算子、コマンド区切り記号、& |および|| &&括弧;でグループ化すること( )-できます。また、私たちが使用したテストコマンド[と引用符がある' "だけでなく、前!のコマンドを呼び出すための感嘆符やハッシュされたコメントを使用し、複数文字と単一文字の#ワイルドカードアスタリスク*と疑問符もあります。?また、現在のディレクトリと親ディレクトリは.および..で、ホームディレクトリはに設定されています~/。つまり、文字; & | > < - [ \ ' " ( ) # * ! ? . ~ ^ { }、、`改行、空白、タブ(およびシングルバイトロケールの他の空白文字)を2回調べる必要がありますが、これらの文字はすべて同じレベルで「危険」ではありません。多すぎるので忘れていないといいですね。

答え4

ファイル名は'/'ディレクトリ区切り文字であるため、使用は禁止されています。これが唯一の理由です。ファイルシステムを手動で編集する場合は、という名前のファイルを作成することも'/'できます(多くの操作を実行できないため、お勧めできません)。

関連するシステムコールは C 言語文字列転送規則を使用し、NUL はその文字列の終端であるため、NUL 文字をファイル名の一部として使用することはできません。したがって、名前の一部として解釈することはできません。

という名前のファイルを生成することは、\0NULを含むファイルを生成するのと同じではありません。前者は'\'2文字のsumを含むファイル名です'0'

関連情報