POSIX sh文字列のすべての改行文字を「\ n」に変換する方法

POSIX sh文字列のすべての改行文字を「\ n」に変換する方法

改行文字を含む文字列があります。この文字列のすべての改行文字を2つの文字列「\ n」に置き換えてエスケープしたいと思います。 POSIX shでこれを行うにはどうすればよいですか?

目標は次のとおりです。

$ printf 'a\nb\nc\nd' | escape_newlines | od -a
0000000   a   \   n   b   \   n   c   \   n   d
        141 134 156 142 134 156 143 134 156 144
0000012

それをどのように定義しますかescape_newlines

私が試したこと:

  • tr- 問題:単一の文字を複数の文字に変換できません。

  • awk 'BEGIN{ORS="\\n"} {print}'— 問題: 文字列が改行文字で終わらない場合でも、2 つの文字列 "\n" が常に文字列の末尾に挿入されます。例:

    $ printf 'hi\n' | awk 'BEGIN{ORS="\\n"} {print}' | od -ab
    0000000   h   i   \   n
            150 151 134 156
    0000004
    $ printf 'hi' | awk 'BEGIN{ORS="\\n"} {print}' | od -ab
    0000000   h   i   \   n
            150 151 134 156
    0000004
    
  • sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g'- 問題:文字列の末尾に改行文字がある場合、変換されません。例:

    $ printf 'h\ni' | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g' | od -ab
    0000000   h   \   n   i
            150 134 156 151
    0000004
    $ printf 'h\ni\n' | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g' | od -ab
    0000000   h   \   n   i  nl
            150 134 156 151 012
    0000005
    

答え1

以下を試してくださいawk

string='x
y
'
new_string=$(
  LC_ALL=C awk -- '
    BEGIN {
      gsub("\n", "\\n", ARGV[1])
      printf "%s", ARGV[1]
    }' "$string"
)

それにもかかわらず、コマンドの置き換えは末尾の改行を削除することに注意してください。の出力には何も含まれていないため、ここでは問題はありません。awkしかし、これはprintprintf "%s"

そしてsed

new_string=$(
  printf '%s\n' "$string" |
    LC_ALL=C sed '
      :1
      $ ! {
        N
        b1
      }
      s/\n/\\n/g'
)

POSIXによると、N最後の行に使用することは、パターンスペースを捨てて終了することを意味します。 GNUは環境内にのみこれを行いますsedが、最後の行で呼び出された場合でも終了します(ただしパターンスペースを印刷します)。$POSIXLY_CORRECTN

LC_ALL=Cユーザーロケールの文字マップから文字列をデコードするときに発生する可能性がある問題を回避するためにこれを使用します。

sedテキストユーティリティなので、テキスト入力を受け取り、テキスト出力を生成します。空ではなく改行文字で終わらない内容はテキストではありません。ここでは、入力に改行文字を追加し、コマンド置換を使用して追加されたsed改行文字を出力から削除します。

また、入力行の長さがLINE_MAXバイト(1024と同じくらい低くなる可能性があります)より長い場合、テキストではなく状態になり、動作は指定されません。 IIRCでは、パターンスペースが10 x LINE_MAX以上を収容する必要もありません。

このawk方法には、ARG_MAX から始まり、システムの 10 x LINE_MAX より低い制限がいくつかあります。この制限は、組み込まれていないシェル(ksh88やpdkshベースのシェルなど)sedにも適用されます。printf

シェル変数のサイズに制限はありませんが、環境にエクスポートされると、実行されるすべての外部コマンドのARG_MAX制限に従って実行されます。

ストリームを処理するには、次のものが必要です。

... | (cat; echo) | LC_ALL=C awk '
  {printf "%s", sep $0; sep = "\\n"}'

ただし、出力はテキストではないため、POSIXテキストユーティリティでは処理できません。

関連情報