私のシェルはダッシュです。私の問題は次のとおりです。
# A="abc\nde fg"
# printf "$A"
abc
de fg#
# B="abc\\nde fg"
# printf "$B"
abc
de fg#
# C="abc\\\nde fg"
# printf "$C"
abc\nde fg#
私が使用している文字列変数には、スペースと\n
の両方、および場合によっては他の空白文字が含まれています。文字列内の$A
をエスケープせずに、変数\n
にアクセスしたいと思います。一重引用符を使用しても変数として解釈されず、二重引用符を使用するとそれらの特殊文字が解釈されます。
ダッシュには、そうするための方法がシェルに組み込まれていますか?文字列内のエスケープ文字のバックスラッシュを2倍にする外部プログラムに変数を送信できることは知っていますが、それは間違っていると感じます。
printf
の間違いに気づきましたが、この場合は関係ありません。当初、私はecho
を使用していました。これは私が求めていることのより良い例です。これはまったく同じコマンドシーケンスの2つで、最初のシーケンスのみがbashで、2番目のコマンドシーケンスはダッシュで示されています。
$ cat sample.txt
abc\nde fg
some string
$ A=`cat sample.txt`
$ echo "$A"
abc\nde fg
some string
$
$ cat sample.txt
abc\nde fg
some string
$ A=`cat sample.txt`
$ echo "$A"
abc
de fg
some string
$
この一連のコマンドでダッシュが\n
を解釈できないかどうか知りたいのですが。外部コマンドを使用して回避策をすでに実装しました。 printf
を適切に使用することで私が望むことはできますが、ダッシュシェル自体にこれを独自に行う方法があるかどうかを知りたいと思います。
完全を期すために、質問が出た理由は次のとおりです。ファイルを読んで、下の部分に条件付きでコメントまたはコメントを外す必要があります。最初の部分にはリテラル\n
(改行ではない)があり、書き換えられたファイルでそのように維持する必要があります。
バッククォートで囲まれたsedを使用してファイルを2つに分割し、それらを変数に割り当てます。最後に、"$VAR1$VAR2"
のようなことを行うだけで変数を連結します。ここで、$VAR2
はすでに条件付きでコメントされているか、コメントされていないか、そのままになっています。
問題は、BashとDashの両方にecho
が組み込まれていることですが、\
を含む文字列を指定すると、2つの実装は同じように動作しません。
echo 'abc\ndef'
これにより、2つのシェルで異なる結果が生成されます。
printf '%s\n'
;を使用すると、一貫した出力を得ることができます。これも組み込みですが、両方のシェルで同じ出力を生成します(これは、すべての変換に当てはまるわけではありません。たとえば、bashはダッシュではない%q
変換を提供します):
printf '%s\n' 'abc\ndef'
これにより、両方のシェルでabc\ndef
が生成されます。
あるいは、echo
の外部実装を使用することもできます。 Linuxでは、coreutils
はGNU /bin/echo
にエコーします:
/bin/echo 'abc\ndef'
ただし、これは移植性が低いことに注意してください。 GNU情報ファイルには次のように書かれています:
POSIXはオプションのサポートを必要とせず、文字列にバックスラッシュが含まれている場合、または最初の引数が
-n
の場合、echo
の動作は実装によって定義されると述べています。ポータブルプログラムは、末尾の改行を省略したり、制御文字や円記号を出力したりする必要がある場合に、printf
コマンドを使用できます。
いいえ、echo
には多くのバリエーションがあります。 echo
は移植可能なコマンドではありません。
dash
のecho
は、実際にはUNIXに準拠した数少ないecho
実装の1つです(少なくとも、dash
はマルチバイトに対応していないため、たとえば、マルチバイトロケールをサポートするシステムに準拠していない他の領域です)。
UNIX仕様では、
echo '\n'
2つの改行文字を出力し、
echo -e x
出力する-e x<newline>
。
AT&T ksh
、bash
、yash
、zsh
などの他のシェルには、echo
ビルトインの動作を変更する設定があります( GNU echo
コマンドも環境の影響を受ける可能性があります)の動作は、現在dash
には当てはまりません。
いずれにせよ、echo
を使用して任意のデータを出力することは望ましくありません。そのための標準的で移植可能なコマンドはprintf
です。
printfがechoよりも優れている理由 の回答で、echo
の周りのラッパー関数として別のprintf
を実装する方法などの詳細を見つけることができます。
printf
を、フォーマット文字列によって補間された値ではなく、フォーマット文字列として使用しています。
echo
を使用するか、printf
を意図したとおりに使用してください。ここではいくつかの例を示します。
A="abc\nde fg" B="abc\\nde fg" C="abc\\\nde fg"
echo "$A"
abc\nde fg
echo "$B"
abc\nde fg
echo "$C"
abc\\nde fg
printf "%s\n" "$A"
abc\nde fg
printf "Here is variable B: %s\n" "$B"
Here is variable B: abc\nde fg
printf "> %s <\n" "$C"
> abc\\nde fg <
ちなみに、二重引用符で囲まれた文字列を使用することにより、それらは解析され、円記号\
が処理されます。一重引用符で囲まれた文字列を使用して変数を定義すると、\
文字のセット全体を保持することもできます。
A='abc\nde fg' B='abc\\nde fg' C='abc\\\nde fg'
echo "$A"
abc\nde fg
echo "$B"
abc\\nde fg
echo "$C"
abc\\\nde fg