当サイトではアフィリエイト広告を利用しています。

【初心者向け】シェルスクリプトで変数に入れたコマンド結果の改行が消える問題の原因と対処法【bash multiline newline loss】

シェルスクリプトを書いていると、コマンドの結果を変数に代入したときに、元々あった改行がすべて消えてしまい、一行の文字列として扱われることがあります。

例えば、toppsのような複数行の出力を変数に入れて処理したいのに、改行がなくなり見づらくなったり、意図した処理ができなくなったりして困った経験はありませんか?

これはシェルの基本的な仕様によるもので、多くの初心者がつまずく典型的な問題です。

本記事では、

  • なぜ改行が消えてしまうのか?
  • どうすれば改行を含めて変数に保存・展開できるのか?
  • 実際に使える安全な書き方

を、根拠ある情報を交えながらわかりやすく解説します。

シェル変数に代入したテキストの改行が消える現象とは?

例えば以下のようなシェルスクリプトを考えてみましょう。

#!/bin/bash

output=$(ls -l /etc)

echo "変数に入れた内容を表示"
echo $output

このスクリプトを実行すると、ls -l /etc の結果は複数行に渡るはずですが、実際はすべての改行が消え、スペース区切りの一行の文字列として表示されてしまいます。

-rw-r--r-- 1 root root 1234 Jun 1 12:00 file1.conf -rw-r--r-- 1 root root 2345 Jun 2 12:00 file2.conf ...

これは変数展開時に、シェルが空白・改行を区切り文字として「単語」に分割し、それをスペースで繋ぎ直すために起こる現象です。

改行が消える原因を詳細に解説

1. POSIXシェルのワード分割

シェルは変数展開時に「単語分割(word splitting)」を行います。
デフォルトの区切り文字は $IFS (Internal Field Separator)変数に設定されており、一般的には空白、タブ、改行が含まれています。

つまり、変数の中身に改行があっても、展開時にそこを区切りとして分割され、echoなどに渡される段階でスペースに変換されてしまうのです。

2. 変数展開時のクォーテーションの重要性

echo $output と書くと、変数展開時にワード分割が発生し改行が消えます。

一方、echo "$output" とダブルクォーテーションで囲むと、ワード分割が抑制され改行を含む文字列がそのまま渡されます。

この違いは次のように試せます。

echo $output    # 改行がスペースに置き換わる
echo "$output"  # 改行が保持される

3. 変数代入時の展開について

変数代入時にも注意が必要です。

text=$(ls -l)

ここで、$(ls -l) の結果はそのまま変数に格納されますが、改行は保持されています。

しかし、展開時にダブルクォーテーションで囲わないと改行は消えます。

改行を保持して変数に格納・展開する具体的な対策

1. 変数代入時はダブルクォーテーションで囲む☆

output="$(ls -l)"

これで変数に改行込みで格納されます。

2. 変数展開時もダブルクォーテーションで囲う☆

echo "$output"

これで改行を含めてそのまま表示されます。

大抵はこの2つの対策で解決します!

3. echoではなくprintfを使う

echo はシェル環境やバージョンによって挙動が異なるため、安定した結果を出したい場合はprintfを使うのが望ましいです。

printf '%s\n' "$output"

4. ヒアドキュメントを使う

ヒアドキュメントであれば長い複数行の文字列を扱いやすいです。

cat <<EOF > output.txt
$output
EOF

5. IFSを一時的に変更する方法(高度テク)

IFSを改行のみに限定してワード分割を制御する方法もありますが、初心者にはやや複雑なので必要に応じて紹介します。

よくある誤りとトラブルシューティング

1. ダブルクォート忘れ

output=$(ls -l)
echo $output  # NG!改行消える

2. シングルクォートで囲んでしまう

output='$(ls -l)'
echo "$output"  # コマンド展開されずそのまま文字列に

3. read コマンドでの扱い

read コマンドはデフォルトで改行を区切りに読み込むため、複数行は扱いにくい。IFS-dオプションの活用が必要。

4. シェルの種類による違い

bash, sh, zsh で微妙に挙動が異なる場合があるため、スクリプト実行環境を意識すること。

まとめ

  • シェルスクリプトで改行を含むテキストを変数に格納するときは
    • 代入時にダブルクォーテーションで囲う※重要
    • 展開時にもダブルクォーテーションで囲う※重要
  • echoではなくprintfの利用を推奨
  • IFSの設定やシェル種の違いにも注意が必要