Pythonなどでの改行
シェルスクリプトの前に、Pythonなどの言語では
\n
が改行コードになっていて、
>>> a = """abc
xyz"""
>>> print(a)
abc
xyz
>>> print(repr(a))
'abc\nxyz'
>>> b = "abc\nxyz"
>>> print(b)
abc
xyz
>>> print(repr(b))
'abc\nxyz'
>>> a == b
True
>>> "\n" in a
True
>>> "\n" in b
True
といった感じに改行を直接書いても文字列中では\n
として入れられて
print
などの出力ではそれを変換して出力している形になっています。
大概の言語ではこんな感じになってるかと思います。
シェルスクリプトでの\n
シェルスクリプト中でも\n
を入れると出力が改行になることがあります。
$ b="abc\nxyz"
$ printf "$b"
abc
xyz
ただ、echo
とかだと
$ b="abc\nxyz"
$ echo "$b"
abc\nxyz
となって\n
が残ります。
これはBashのbuiltinのecho
であれば
$ b="abc\nxyz"
$ echo -e "$b"
abc
xyz
と-e
オプションを使えば変換してくれます。
一方で、改行を直接入れると
$ a="abc
xyz"
$ printf "$a"
abc
xyz$ echo "$a"
abc
xyz
$ echo -e "$a"
abc
xyz
とオプションなしのecho
でも改行してくれます。
比較して見ると
$ if [ "$a" = "$b" ];then echo SAME;else echo DIFF;fi
DIFF
となって違うものとして保存されていることがわかります。
シェルスクリプトでの$’\n’
Bashでは改行と\n
は同義ではないですが、
BashにはANSI-C Quoting
という特殊文字があり、この中に
$'\n'
という
改行が定義されています。
この文字はクォートの中だと通常の文字として認識されてしまうので、その部分だけはクォート外にする必要があります。
$ c="abc"$'\n'"xyz"
$ printf "$c"
abc
xyz$ echo "$c"
abc
xyz
$ echo -e "$c"
abc
xyz
この文字列は実際に改行を書いた場合と比べると
$ if [ "$a" = "$c" ];then echo SAME;else echo DIFF;fi
SAME
ということで同じものとして認識されています。
クォートの中に入れると
$ d="abc$'\n'xyz"
$ printf "$d"
abc$'
'xyz$ echo "$d"
abc$'\n'xyz
xyz
$ echo -e "$d"
abc$'
'xyz
な感じでprintf
とかでは$
や'
を単なる文字として認識して\n
の部分だけを改行として変換して出力するようになります。
この$'\n'
に関しては$'012'
もしくは$'x0A'
(共に8進法と16進法での10、ASCIIコードでのLF
(改行)を表すもの)
としても全く同じものとして認識されます。
$ e="abc"$'\012'"xyz"
$ f="abc"$'\x0A'"xyz"
$ if [ "$a" = "$e" ];then echo SAME;else echo DIFF;fi
SAME
$ if [ "$a" = "$f" ];then echo SAME;else echo DIFF;fi
SAME
このANSI-C QuotingはZshなどモダンなシェルではサポートされています。
Ubuntuなどの/bin/shになっているdash
などだとサポートされておらず、
$ dash
$ a="abc
xyz"
$ c="abc"$'\n'"xyz"
$ if [ "$a" = "$c" ];then echo SAME;else echo DIFF;fi
DIFF
$ echo "$a"
abc
xyz
$ echo "$c"
abc$
xyz
みたいな感じで$
が単に文字列とみなされ、'
は\n
をクォートしたものとみなされて削除されています。