web-dev-qa-db-ja.com

ダッシュで円記号を使用して変数を出力します

私のシェルはダッシュです。私の問題は次のとおりです。

# 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番目のコマンドシーケンスはダッシュで示されています。

bash

$ 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はすでに条件付きでコメントされているか、コメントされていないか、そのままになっています。

1
jmarsh411

問題は、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コマンドを使用できます。

2
Toby Speight

いいえ、echoには多くのバリエーションがあります。 echoは移植可能なコマンドではありません。

dashechoは、実際にはUNIXに準拠した数少ないecho実装の1つです(少なくとも、dashはマルチバイトに対応していないため、たとえば、マルチバイトロケールをサポートするシステムに準拠していない他の領域です)。

UNIX仕様では、

echo '\n'

2つの改行文字を出力し、

echo -e x

出力する-e x<newline>

AT&T kshbashyashzshなどの他のシェルには、echoビルトインの動作を変更する設定があります( GNU echoコマンドも環境の影響を受ける可能性があります)の動作は、現在dashには当てはまりません。

いずれにせよ、echoを使用して任意のデータを出力することは望ましくありません。そのための標準的で移植可能なコマンドはprintfです。

printfがechoよりも優れている理由 の回答で、echoの周りのラッパー関数として別のprintfを実装する方法などの詳細を見つけることができます。

4

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
2
roaima