それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

bashで複数行の文字列の代入と、ヒアドキュメントを使わずに変数に格納する方法

bash で複数行の文字列を変数に格納する方法

「改行が入らない」ではなく、「改行が見えない」のです。入らないと思って改行を調べてしまう事例が多いです。注意しましょう

その1:一番シンプルなのはそのまま

str="
ここは
サンプル
の複数行文字列
です。
"
echo "$str"

echo $str ではなく、 echo "$str" なのがちょっと味噌ですね

その2:ヒアドキュメント編

一般的なのは、ヒアドキュメントをつかって定義する方法。インターネットを探すとコッチが多いんだけど、なぜわざわざcatを呼び出す無駄なことをしているのか理解できない。dash/bash/zsh でもサンプル1で動くのに。

str=$(cat <<EOS
ここは
サンプル
の複数行文字列
です。
EOS
)
echo "$str"

なぜ "$str" とクオートが必要なのか?

クオートが必要なのは、改行を含めた文字列が「変数に格納」されていて、出力時に「分割」されるからとかんがえられる

次のように定義したとき

str="a
b
c

出力前に、先に変数展開がされます。

echo $str

echo a 
b 
c

となり、IFSで分割されて

echo a b c 

となってると考えられます。

これを確かめるために、IFSをオフにして実験してみます。

実験:IFS をオフにして "$str" を不要にした。

str="
ここは
サンプル
の複数行文字列
です。
"
IFS=''
echo $str

ifs でbash の区切り文字を変えることがポイント

実行結果

takuya@2017-03-21#7$ bash   sample.sh

ここは
サンプル
の複数行文字列
です。

此の実験結果から分かる通り、変数には改行付きで格納されてることがわかります。

bash はコマンドを1行読み込むと、変数展開をします。展開後文字列にIFSを適用し、実行する。そのため一般的に"$str" とダブルクオートで囲む解決策が頻用されると考えれます。

その3:ヒアストリング

コマンドにヒアストリングを渡すことが出来ます。

cat <<< "here string"

これを応用して、次のように書けます。

str=$(cat <<<"
ここは
サンプル
の複数行文字列
です。
")
echo "$str"

インデントもしたい

ソースコードの可読性向上にインデントを企図してるときは、ヒアドキュメントが有能です。

cat <<-EOF
    ここは
            サンプル
            の複数行文字列
            です。
    EOF

-EOF と、ダッシュをつけることで先頭のタブ文字を捨ててくれます。タブ文字だけですよ?expandtab しててスペースはに置換してたら動きません。

繰り返しになりますが、インデントに使えるのはTAB文字だけですよ?

bash 4 からの新機能 mapfileを使う場合

StringIO#lines 的なことで解決する場合

mapfile str <<EOF
ここは
サンプル
の複数行文字列
です。
EOF

echo "${str[@]}"

MapFileは、ファイル(この場合はstdinのfd)を複数行に分割し、配列に格納してくれます。これを使うともっと楽にできます。

注意 パイプはできない

次のパイプはエラーになります。

echo "aa
bbb" | cat 

パイプに書くときは一旦変数に入れます。

str="aaa
bbb
"
echo $str | cat 

参考資料

2021-02-16

ifs で検索されないので ifsを明示的に指定した

2022-04-18

パイプについて追記。