$ printf "hi"
hi$ printf "hi\n"
hi
$ printf "hi\\n"
hi
最終行が印刷されないのはなぜですかhi\n
?
これはprintf
とは関係がなく、printf
に指定した引数と関係があります。
二重引用符で囲まれた文字列では、シェルは\\
を\
に変換します。したがって、printf
に指定した引数は実際にはhi\n
であり、もちろんprintf
はits ownエスケープシーケンス処理を実行します。
二重引用符で囲まれた文字列では、シェルによって\
を介して行われるエスケープは、specifically、\
、`
、$
、および"
の文字にのみ影響します。 \n
がprintf
にそのまま渡されることがわかります。したがって、printf
に指定した引数は、実際にはhi\n
againです。
エスケープシーケンスをprintf
のフォーマット文字列に入れる場合は注意してください。 一部のみSingle Unix Specificationで定義された意味があります。たとえば、\n
は定義されていますが、\c
は実際には定義されていません。
二重引用符内では、\\n
はエスケープされた(引用符で囲まれた)バックスラッシュの後にn
が続きます。 \n
とprintf
は改行を出力するため、これはprintf
に渡されます。
二重引用符内で(まだ)、\n
は文字列\n
です。再び、printf
は\n
文字列を受け取り、改行を出力します。
二重引用符内では、別のバックスラッシュ、改行、または$
、`
、または"
の前にある場合、バックスラッシュは特別なonlyです。 「特別」とは、次の文字の特別な意味を取り除くことを意味します。バックスラッシュが他の文字の前にある場合(たとえば、n
)、それは単なるバックスラッシュ文字です。
これは POSIX標準 で説明されています。
\n
をprintf
形式の文字列で出力するには、printf '\\n'
またはprintf "\\\\n"
を使用するか、printf '%s' '\n'
を使用します
一般に、printf
フォーマット文字列は一重引用符で囲み、変数データはフォーマット文字列に挿入する追加の引数として指定する必要があります。
printf 'This is how you write a newline: %s\n' '\n'
では、別の視点を追加しましょう。
ここでは、2つのレベルの解釈があります。 1つはシェルで、もう1つは受け取った引数のコマンド(この場合はprintf
)解釈です。
二重引用符の内側シェルはほとんどのシーケンスのバックスラッシュ文字をそのままにします。これは一般的な結果です:
$ printf '%s\n' "\a \b \c \d ... \z \$ \` \\ "
\a \b \c \d ... \z $ ` \
Exceptwith $
、`
、および\
は、シェルにとって特別であり、それらの\
を削除しました。
したがって、使用した両方の文字列(およびその他)をテストすると、次のようになります。
$ printf '%s\n' "hi\n" "hi\\n" "hi\\\n" "hi\\\\n" "hi\\\\\n"
hi\n
hi\n
hi\\n
hi\\n
hi\\\n
シェルは、\\
のペアを1つの\
に変換します。そして、そのまま\n
を\n
のままにします。
現在、printf
は最初の引数と特別な関係にあり、the format
に明示的に設定されています。 format引数では、一部の文字は(printfにとって)特殊です。たとえば、%
文字およびで始まる有効なシーケンス- バックスラッシュ文字のシーケンス のように:
\\ \a \b \f \n \r \t \v and the special \ddd
したがって、文字列\n
は改行を生成しますが、\\n
は生成しません。
$ printf " hi\n hi\\n hi\\\n hi\\\\n"; echo
hi
hi
hi\n hi\n