【Linux】echo・printfの使い方|-e/-nの罠・シェルによる違い・書式指定とゼロ埋め

【Linux】echo・printfの使い方|-e/-nの罠・シェルによる違い・書式指定とゼロ埋め Linux

echoprintfは、どちらも文字列を出力するコマンドです。echoは「とにかく手軽に1行出す」のに向き、printfは「書式を指定して、桁揃えやゼロ埋めまで細かく整形する」のに向いています。シェルスクリプトでメッセージを表示したり、整形した表を出力したりと、地味ながら毎日使う基本コマンドです。

ただし、echoには意外と落とし穴があります。タブや改行を出力するための-eオプションが、シェルの種類によって効いたり効かなかったりするのです。同じスクリプトでも、bashで動かすかshで動かすかで結果が変わってしまいます。この記事では、実機のLinux(WSLのDebian)でこの違いを実際に再現しながら、echoprintfの使い方と、移植性の高い書き方を整理します。

先に結論

  • echo 文字列で1行出力(末尾に改行が自動で付く)。
  • echo -nで改行なし、echo -eでタブ\tや改行\nを有効化します。
  • echo -eはシェルによって動作が違う(sh/dashでは-eがそのまま出る)ため移植性が低いです。
  • エスケープや整形を確実にしたいならprintfを使うのが安全です。
  • printf改行を自動で付けません\nを明示します)。
  • printf "%05d"のように、ゼロ埋め・桁揃え・書式指定ができます。

出力先を切り替えるリダイレクトはリダイレクトとパイプ、シェルスクリプトでの活用は環境変数aliasもあわせて参考になります。

スポンサーリンク

echoの基本(-n / -e)

echoは文字列を出力し、末尾に自動で改行を付けます-nを付けると改行なし、-eを付けるとタブや改行などのエスケープシーケンスが有効になります。

echo の基本
# 基本(末尾に改行が付く)
echo "Hello World"

# -n: 末尾の改行を付けない
echo -n "no newline"
# no newline(改行されず、次の出力が続く)

# -e: エスケープを有効化(\t=タブ, \n=改行)
echo -e "col1\tcol2\nrow2"
# col1    col2
# row2

実機でも、echo -n末尾の改行が付かないこと、echo -e "col1\tcol2\nrow2"タブと改行が展開されて2行に整形されることを確認しました。-eを付けないと、次で見るように\t\nそのまま文字として出力されてしまいます。

【罠1】-eを付けないとエスケープが文字のまま出る

echoで改行やタブを出したいのに、-eを付け忘れると、\t\nという文字がそのまま表示されます。「改行させたいのに、なぜか\nがそのまま出る」というのはよくある失敗です。

-e忘れの挙動
# -e を付けないと…
echo "tab\there"
# tab\there     ← \t がそのまま文字として出る

# -e を付ければタブになる
echo -e "tab\there"
# tab     here

実機でも、echo "tab\there"-eなし)はtab\thereとそのまま出力され、-eを付けて初めてタブとして展開されました。「エスケープを使いたいときは-e」を忘れないようにしましょう。ただ、この-e自体にさらに大きな落とし穴があります。

【罠2・最重要】echoの挙動はシェルで変わる

ここがechoの最大の問題点です。echoの動作は、使っているシェルによって異なります。とくにsh(多くのLinuxではdash)では、-eがオプションとして認識されず、-eという文字がそのまま出力されてしまいます。

bashとshで結果が違う(実証)
# bash では -e が効く
bash -c 'echo -e "a\tb"'
# a       b      ← タブになる

# sh(dash) では -e が効かず、そのまま出る
sh -c 'echo -e "a\tb"'
# -e a    b      ← 「-e」が文字として出力されてしまう!
echo -eは移植性が低い・printfを使うべき(実証)

実機で、まったく同じecho -e "a\tb"というコマンドを、bashsh(dash)で実行して比べました。bashではa[タブ]bと正しく展開されましたが、shでは-e a[タブ]bと、先頭に-eという文字がそのまま出力されてしまいました。多くのLinuxディストリビューションでは、#!/bin/shで始まるスクリプトやsh script.shでの実行時にdashが使われるため、「bashでは動いたスクリプトが、shで実行したら-eが出力に混ざる」という事故が起こり得ます。これはechoの仕様がシェルによって異なることが原因で、根本的には避けようがありません。だからこそ、タブや改行を含む出力を確実に行いたいときは、シェルによらず同じ動作をするprintfを使うのが、プロによる定番の解決策です。echoは「単純な1行メッセージ」に留め、整形が必要ならprintf——と使い分けるのが安全です。

printfの基本:改行は自動で付かない

printfは、C言語のprintfと同じ考え方で書式を指定して出力するコマンドです。echoと違う最初のポイントは、末尾に改行が自動で付かないことです。改行したいときは\nを明示的に書きます

printf の基本
# printf は改行を自動で付けない
printf "no auto newline"
# no auto newline(改行なしで次に続く)

# 改行したいなら \n を明示する
printf "with newline\n"
# with newline

# printf のエスケープはシェルによらず常に有効
printf "a\tb\n"
# a       b      ← bash でも sh でも同じ結果になる

実機でも、printf "no auto newline"改行されずprintf "with newline\n"明示的に改行されることを確認しました。そしてprintfのエスケープ(\t\n)は、bashでもshでも常に同じように展開されます。この「シェルによらず一貫している」という性質が、printfが推奨される最大の理由です。「改行を自分で書く」というひと手間はありますが、そのぶん結果が予測可能で信頼できます

printfの書式指定(%s / %d / %f)

printfの真価は書式指定子にあります。%s(文字列)・%d(整数)・%f(小数)などのプレースホルダを書式に埋め込み、その後に値を並べると、対応する位置に値が差し込まれます。

書式指定子で整形
# %s=文字列, %d=整数, %.2f=小数点2桁
printf "%s is %d years, %.2f score\n" "taro" 30 87.5
# taro is 30 years, 87.50 score

# %x=16進, %o=8進
printf "hex=%x oct=%o\n" 255 8
# hex=ff oct=10

実機でも、printf "%s is %d years, %.2f score\n" "taro" 30 87.5taro is 30 years, 87.50 scoreと、各プレースホルダに値が正しく差し込まれました。%.2f小数点以下2桁を意味し、87.587.50と整形されます。%x(16進)や%o(8進)を使えば、数値の基数変換もできます(255ff)。awkと同じ書式指定の考え方なので、あわせて覚えると応用が利きます。

ゼロ埋め・桁揃えと書式の繰り返し

printfは、ゼロ埋め(%05d)や桁揃え(%-10sで、表形式のきれいな出力を作れます。さらに、値が書式より多いと、書式が繰り返し適用される便利な性質もあります。

ゼロ埋め・桁揃え・繰り返し
# %05d: 5桁でゼロ埋め
printf "%05d\n" 42
# 00042

# %-10s(左寄せ10桁)と %10s(右寄せ10桁)
printf "%-10s|%10s|\n" "left" "right"
# left      |     right|

# 値が多いと、書式が繰り返される
printf "item: %s\n" apple banana cherry
# item: apple
# item: banana
# item: cherry
ゼロ埋め・桁揃え・書式の自動繰り返し(実証)

実機で確認したところ、printf "%05d\n" 4200042と5桁ゼロ埋めになり、printf "%-10s|%10s|\n" "left" "right"left      |     right|と、左寄せ・右寄せの桁揃えが正しく行われました。%-10s-は左寄せ、数字は最小の桁数を表します。さらに面白いのが、printf "item: %s\n" apple banana cherryのように書式の中のプレースホルダより値が多い場合、書式が値の数だけ繰り返し適用されることです(実機でもapple・banana・cherryが3行に展開されました)。この性質を使うと、配列やリストを1つのprintfできれいに整形できます。連番のファイル名(file_%03dfile_001…)を作ったり、ログを揃えて出力したりと、printfechoにはできない整形を数多くこなせます。

主な書き方一覧

echoprintfの要点をまとめます。

書き方 働き
echo 文字列 1行出力(改行が自動で付く)
echo -n / -e 改行なし / エスケープ有効(移植性は低い)
printf "書式" 値... 書式指定で出力(改行は\nを明示)
%s / %d / %.2f 文字列 / 整数 / 小数2桁
%05d / %-10s ゼロ埋め / 左寄せ桁揃え
エスケープを確実に echo -eよりprintfが安全

よくある失敗

echoで\nがそのまま出て改行されない

エスケープには-eが必要です。ただし確実にしたいならprintfを使います。

bashで動いたのにshでecho -eの-eが出力される

echoの挙動はシェル依存です。移植性が必要ならprintfに置き換えます。

printfで改行されない

printfは改行を自動で付けません。末尾に\nを書きます。

printfの書式と値の数が合わない

値が多いと書式が繰り返されます。意図しない繰り返しに注意します。

printfに%を文字として出したい

%%と書くと、リテラルの%が出力されます。

よくある質問

Qechoで改行やタブを出力するには?
Aecho -eを付けると、\n(改行)や\t(タブ)などのエスケープが有効になります。ただし-eの挙動はシェルによって異なり、sh(dash)では-eが文字として出力されてしまいます。確実に改行やタブを出したいときは、シェルによらず同じ動作をするprintfを使うのがおすすめです。
Qbashでは動くのにshでechoの-eが出力されてしまいます。
Aechoの仕様がシェルによって異なるためです。bashのecho-eをオプションとして解釈しますが、sh(多くの環境ではdash)は-eを認識せず、そのまま文字列として出力します。実機でもこの違いを確認しています。移植性が必要なスクリプトでは、echo -eではなくprintfを使ってください。
Qprintfで改行されないのはなぜですか?
Aprintfechoと違い、末尾に改行を自動で付けません。改行したいときは書式の末尾に\nを明示的に書きます(例: printf "hello\n")。このぶん手間はかかりますが、シェルによらず結果が一貫するのがprintfの利点です。
Q数値をゼロ埋めして表示するには?
Aprintf "%05d\n" 42のように書くと、5桁でゼロ埋めされて00042と表示されます。%05d0がゼロ埋め、5が桁数です。連番のファイル名(file_%03dfile_001など)を作るときにも便利です。実機でも正しくゼロ埋めされることを確認しています。
Qechoとprintfはどう使い分けますか?
A単純な1行のメッセージを表示するだけならechoが手軽です。一方、タブや改行を含む出力、ゼロ埋め・桁揃え、小数の桁数指定など、整形が必要な場合や、シェルによらず一貫した動作が必要な場合はprintfを使います。「単純な出力はecho、整形や移植性が要るならprintf」が目安です。

まとめ

  • echoは手軽な1行出力。-nで改行なし、-eでエスケープ有効です。
  • echo -eはシェル依存で移植性が低い(sh/dashでは-eが出力される)。
  • エスケープや整形を確実にしたいならprintfを使います。
  • printf改行を自動で付けない\nを明示)。
  • %s%d%05dなどで書式指定・ゼロ埋め・桁揃えができます。

echoprintfは、出力の基本でありながら、奥に「シェルによる挙動の違い」という落とし穴を持つコマンドです。「単純ならecho、確実・整形ならprintf」という使い分けを覚えておけば、スクリプトの出力で予期せぬ事故を防げます。整形した結果はリダイレクトでファイルに保存したり、パイプで次のコマンドへ渡したりして活用しましょう。