This page is the translated page of PrintASingleQuote written in Japanese.
この問題は何度も質問される内容なので、議論するのに値する問題です。 この良くある質問は awk の短所そのものを示しているのではありません。むしろ、ほとんど常に shell のクォートがシングルクォートと作用しあうことによるものなのです。
8 進数のエスケープシーケンス ('\047') または printf ('printf "%c", 39') を用いてください。 16 進数のエスケープシーケンス ('\x27') を使ってはいけません。 なぜなら、awk の実装による違いがあるのに、括られたテキストと悪いように作用してしまうからです。
it said 'Hello, World!' という文字列を表示して 0 を返すには、以下のようなプログラムで実行できます。
BEGIN { print "it said 'Hello, World!' and then returned 0" exit 0 }
しかしながら、同じことをコマンドラインで実行すると・・・
awk 'BEGIN{print "it said 'Hello, World!' and then returned 0";exit 0}'
・・・shell は 2 つのシングルクォートの間に挿入されているコマンドの文字として Hello, World! を解析しようとして文句を言ってきます。
誰かが考え付くかもしれないと思われる最初の考えはシングルクォートよりもダブルクォートの方の中でプログラムの断片を囲むということですが、これは awk の文字列そのものの構文や $ フィールド参照演算子と非常にまずく作用しあいます。
期待に背いて、次のもっとも明らかな解法、それは 16 進数のエスケープシーケンスですが、これは最初はうまく動作するように見えます。
awk 'BEGIN{print "it said \x27Hello, World!\x27 and then returned 0";exit 0}'
・・・でも、この一貫性は偽りなのです。 gawk, mawk や busybox の awk で以下の断片を実行して、結果を比較してみてください。
awk 'BEGIN{print "\x27foo!\x27"}'
mawk と buxybox の awk は予想通りの文字列を表示しますが、gawk はマルチバイト文字を出力することに注意してください。 Open Group Base Specifications issue 6 の論理章の 3 段目で記述されているように、GNU awk のマニュアルの section 2.2 ("Escape Sequences") で繰り替えされているように、2 文字以上の連続した 16 進数のバイト列を許可してしまうので、'\xHH' の 16 進数の記法は曖昧なのです。 不幸なことに 2 バイト以上が与えられた場合、実装に依存した振る舞いになっていまいます。
幸運なことに、私たちはいつでもナイフとクマの毛皮だけの生活 (8 進数の生活) に戻ることができます。 8 進数のエスケープシーケンスは固定長を持つことが要求されているのです。
awk 'BEGIN{print "\047foo!\047"}'
もしくは printf を使うこともできます。
awk 'BEGIN{printf "%cfoo!%c\n", 39, 39}'
・・・しかし、全てのエスケープシーケンスが対応する数字を与えられていることを確認するところから始めなければなりません。 gawk は文字列シーケンスの中の特定の位置によって printf の引数が再利用されるという特徴 a printf extension があります・・・。
awk 'BEGIN{printf "%1$cfoo!%1$c\n", 39}'
・・・しかし、この妥協は礼儀正しいこの社会にはいささか醜いので、言わなかったことにしておきます。
変数にシングルクォート文字を代入してしまうという古い代案があり、明示的な文字列の連接として使います。
awk 'BEGIN{q="\047";print q"foo!"q}'
・・・しかし、多くのシングルクォートを含むような長い文字列を取り扱う際には醜くなります。
最も清潔な方法はファイルの中でプログラムを書くことです。 クォートの問題で動作するための shell 特有の方法があるかもしれません。 何か他に知っていれば、自由に書き加えてください。