echoとprintfは、どちらも文字列を出力するコマンドです。echoは「とにかく手軽に1行出す」のに向き、printfは「書式を指定して、桁揃えやゼロ埋めまで細かく整形する」のに向いています。シェルスクリプトでメッセージを表示したり、整形した表を出力したりと、地味ながら毎日使う基本コマンドです。
ただし、echoには意外と落とし穴があります。タブや改行を出力するための-eオプションが、シェルの種類によって効いたり効かなかったりするのです。同じスクリプトでも、bashで動かすかshで動かすかで結果が変わってしまいます。この記事では、実機のLinux(WSLのDebian)でこの違いを実際に再現しながら、echoとprintfの使い方と、移植性の高い書き方を整理します。
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 "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 を付けないと… 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 では -e が効く bash -c 'echo -e "a\tb"' # a b ← タブになる # sh(dash) では -e が効かず、そのまま出る sh -c 'echo -e "a\tb"' # -e a b ← 「-e」が文字として出力されてしまう!
実機で、まったく同じecho -e "a\tb"というコマンドを、bashとsh(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 "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.5でtaro is 30 years, 87.50 scoreと、各プレースホルダに値が正しく差し込まれました。%.2fは小数点以下2桁を意味し、87.5が87.50と整形されます。%x(16進)や%o(8進)を使えば、数値の基数変換もできます(255→ff)。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" 42は00042と5桁ゼロ埋めになり、printf "%-10s|%10s|\n" "left" "right"はleft | right|と、左寄せ・右寄せの桁揃えが正しく行われました。%-10sの-は左寄せ、数字は最小の桁数を表します。さらに面白いのが、printf "item: %s\n" apple banana cherryのように書式の中のプレースホルダより値が多い場合、書式が値の数だけ繰り返し適用されることです(実機でもapple・banana・cherryが3行に展開されました)。この性質を使うと、配列やリストを1つのprintfできれいに整形できます。連番のファイル名(file_%03dでfile_001…)を作ったり、ログを揃えて出力したりと、printfはechoにはできない整形を数多くこなせます。
主な書き方一覧
echo・printfの要点をまとめます。
| 書き方 | 働き |
|---|---|
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に%を文字として出したい
%%と書くと、リテラルの%が出力されます。
よくある質問
echo -eを付けると、\n(改行)や\t(タブ)などのエスケープが有効になります。ただし-eの挙動はシェルによって異なり、sh(dash)では-eが文字として出力されてしまいます。確実に改行やタブを出したいときは、シェルによらず同じ動作をするprintfを使うのがおすすめです。echoの仕様がシェルによって異なるためです。bashのechoは-eをオプションとして解釈しますが、sh(多くの環境ではdash)は-eを認識せず、そのまま文字列として出力します。実機でもこの違いを確認しています。移植性が必要なスクリプトでは、echo -eではなくprintfを使ってください。printfはechoと違い、末尾に改行を自動で付けません。改行したいときは書式の末尾に\nを明示的に書きます(例: printf "hello\n")。このぶん手間はかかりますが、シェルによらず結果が一貫するのがprintfの利点です。printf "%05d\n" 42のように書くと、5桁でゼロ埋めされて00042と表示されます。%05dの0がゼロ埋め、5が桁数です。連番のファイル名(file_%03dでfile_001など)を作るときにも便利です。実機でも正しくゼロ埋めされることを確認しています。echoが手軽です。一方、タブや改行を含む出力、ゼロ埋め・桁揃え、小数の桁数指定など、整形が必要な場合や、シェルによらず一貫した動作が必要な場合はprintfを使います。「単純な出力はecho、整形や移植性が要るならprintf」が目安です。まとめ
echoは手軽な1行出力。-nで改行なし、-eでエスケープ有効です。echo -eはシェル依存で移植性が低い(sh/dashでは-eが出力される)。- エスケープや整形を確実にしたいなら
printfを使います。 printfは改行を自動で付けない(\nを明示)。%s・%d・%05dなどで書式指定・ゼロ埋め・桁揃えができます。
echoとprintfは、出力の基本でありながら、奥に「シェルによる挙動の違い」という落とし穴を持つコマンドです。「単純ならecho、確実・整形ならprintf」という使い分けを覚えておけば、スクリプトの出力で予期せぬ事故を防げます。整形した結果はリダイレクトでファイルに保存したり、パイプで次のコマンドへ渡したりして活用しましょう。
- grep(文字列検索)
- find(ファイル検索)
- sed(置換・行編集)
- awk(列抽出・集計)
- cut(列の切り出し)
- chmod(パーミッション)
- tar(圧縮・解凍)
- リダイレクトとパイプ
- echo・printf(文字列出力)
- ps・kill(プロセス管理)
- 環境変数とPATH
- ln(シンボリックリンク)
- cp・mv・rm(コピー/移動/削除)
- touch・mkdir(ファイル/フォルダ作成)
- history(コマンド履歴)
- curl(HTTP通信・API)
- jq(JSON処理)
- vim(基本操作・終了方法)
- cron・crontab(定期実行)
- date(日付・時刻)
- sort・uniq・wc(並べ替え/集計)
- xargs(一括処理)
- chown・chgrp(所有者/グループ変更)
- diff(ファイル比較)
- du・df(ディスク使用量)
- head・tail(先頭/末尾・ログ監視)
- cat・less(ファイル表示)
- alias(コマンドの別名)
- nohup(SSH切断対策)
- tmux(セッション管理)
- よく使うコマンドまとめ
- cd(ディレクトリ移動)
