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
参考資料
- http://wiki.bash-hackers.org/syntax/redirection
- http://serverfault.com/questions/72476/clean-way-to-write-complex-multi-line-string-to-a-variable
- help mapfile
2021-02-16
ifs で検索されないので ifs
を明示的に指定した
2022-04-18
パイプについて追記。