改行文字を含む文字列があります。この文字列のすべての改行文字を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
しかし、これはprint
。printf "%s"
そしてsed
:
new_string=$(
printf '%s\n' "$string" |
LC_ALL=C sed '
:1
$ ! {
N
b1
}
s/\n/\\n/g'
)
POSIXによると、N
最後の行に使用することは、パターンスペースを捨てて終了することを意味します。 GNUは環境内にのみこれを行いますsed
が、最後の行で呼び出された場合でも終了します(ただしパターンスペースを印刷します)。$POSIXLY_CORRECT
N
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テキストユーティリティでは処理できません。