Qiita に投稿しようと思ったけど書式エラーで貼れなかったのでこっちに貼っておく。
シェルおよびコマンドの種類
- /bin/sh
- /bin/bash
- /bin/bash(xpg_echo)
- /bin/zsh
- /bin/zsh(bsdecho)
- /bin/echo(BSD ECHO)
- /opt/local/bin/gecho(GNU ECHO/MacPorts Coreutils 版)
比較項目
- オプションフラグ
- タブ
- 改行
- 改行抑制
- エスケープ文字
- エスケープ文字(クオート展開)
- ユニコード指定
echo -n ${LINENO} echo -e ${LINENO} echo -E ${LINENO} echo " " echo "\t" echo -e "\t" echo "${LINENO} ${LINENO}" echo "${LINENO}\n${LINENO}" echo -e "${LINENO}\n${LINENO}" echo "${LINENO}\c" echo -e "${LINENO}\c" echo \\e[31m${LINENO}\\e[m echo \\033[31m${LINENO}\\033[m echo \\x1b[31m${LINENO}\\x1b[m echo "\e[31m${LINENO}\e[m" echo "\033[31m${LINENO}\033[m" echo "\x1b[31m${LINENO}\x1b[m" echo -e \\e[31m${LINENO}\\e[m echo -e \\033[31m${LINENO}\\033[m echo -e \\x1b[31m${LINENO}\\x1b[m echo -e "\e[31m${LINENO}\e[m" echo -e "\033[31m${LINENO}\033[m" echo -e "\x1b[31m${LINENO}\x1b[m" echo [32m${LINENO}[m echo "[32m${LINENO}[m" echo $'\e[31m'${LINENO}$'\e[m' echo $'\x1b[31m'${LINENO}$'\x1b[m' echo $'\033[31m'${LINENO}$'\033[m' echo \\uf8ff LANG=ja_JP.eucJP echo \\uf8ff LANG=ja_JP.UTF-8 echo \\uf8ff
比較表
環境によって結果が異なる可能性があります。元データはページ下部にあります。
○:正しく展開もしくは認識される
△:展開されるが一部問題がある
×:展開されない
?:マニュアル上では使用可能なはずなのに何故か展開されない?
/bin/sh | /bin/bash | /bin/bash (xpg_echo) |
/bin/zsh | /bin/zsh (bsdecho) |
BSD ECHO (/bin/echo) |
GNU ECHO | |
---|---|---|---|---|---|---|---|
オプションフラグ | |||||||
-n | ○ | ○ | ○ | ○ | ○ | ○ | ○ |
-e | × | ○ | ○ | ○ | ○ | × | ○ |
-E | × | ○ | ○ | ○ | ○ | × | ○ |
タブ | |||||||
"<ht>" | ○ | ○ | ○ | ○ | ○ | ○ | ○ |
"\t" | ○ | × | ○ | ○ | × | × | × |
-e "\t" | △ *1 | ○ | ○ | ○ | ○ | × | ○ |
改行 | |||||||
"<nl>" | ○ | ○ | ○ | ○ | ○ | ○ | ○ |
"\n" | ○ | × | ○ | ○ | × | × | ○ |
-e "\n" | △ *1 | ○ | ○ | ○ | ○ | × | ○ |
改行抑制 | |||||||
"\c" | ○ | × | × | ○ | × | ○ | × |
-e "\c" | △ *1 | ○ | ○ | ○ | ○ | △ *1 | ○ |
エスケープ文字 | |||||||
\\e | ? | × | ? | × *2 | × *2 | × | × |
\\x1b \\033 |
○ | × | ○ | × *2 | × *2 | × | × |
"\e" | ? | × | ? | ○ | × | × | × |
"\x1b" "\033" |
○ | × | ○ | ○ | × | × | × |
-e \\e | ? *1 | ? | ? | × *2 | × *2 | × | ○ |
-e \\x1b -e \\033 |
△ *1 | ○ | ○ | × *2 | × *2 | × | ○ |
-e "\e" | ? *1 | ○ | ? | ○ | ○ | × | ○ |
-e "\x1b" -e "\033" |
△ *1 | ○ | ○ | ○ | ○ | × | ○ |
エスケープ文字(RAW) | |||||||
<esc> | ○ | ○ | ○ | × *2 | × *2 | ○ | ○ |
"<esc>" | ○ | ○ | ○ | ○ | ○ | ○ | ○ |
クオート展開 | |||||||
$'\e' $'\x1b' $'\033' |
○ | ○ | ○ | ○ | ○ | ○ | ○ |
ユニコード指定 | |||||||
\uXXXX | - | - | - | ○ *3 | - | - | - |
*1:-e
も一緒に出力される。
*2:文法エラーで終了ステータス 1
。
*3:LANG
未設定や LANG=ja_JP.eucJP
などに設定されている場合は使えない。
特徴
/bin/sh
- デフォルトでは
xpg-echo
が有効。 - オプションが一切無い。
\c
による改行抑制が可能。- クオート内外で
\033
と\x1b
は展開されるが\e
は展開されない。(???)
/bin/bash
- デフォルトでは
xpg-echo
が無効。 - オプションは
neE
。 \c
単独で改行抑制は出来ないが-e
と併用すれば可能。xpg_echo
を有効にした場合でも\e
は展開されない。(???)
/bin/bash (xpg_echo)
\e
が使えないことを除いて /bin/zsh とほぼ同じ。
/bin/zsh
\c
による改行抑制が可能。\e
などを用いる場合はクオートが必要。(メタキー誤動作防止用?)\u
や\U
でユニコードでの指定が可能。(設定による)
/bin/zsh(bsdecho)
BSD ECHO(/bin/echo)
- 最も機能が少なく
-n
と\c
のみ使用可能。
GNU ECHO (MacPorts Coreutils 版)
- /bin/bash とだいたい同じ。ただしこちらは
-e
で\e
が展開される。
全てのシェルで同じ出力をする
printf
を使う
printf '\e[m31mfoobar\e[m\n'
メモ:Autoconf によって生成される configure なんかでは printf
を使った as_echo
、as_echo_n
変数が設定されていたりする。
as_echo='printf %s\n' as_echo_n='printf %s' $as_echo "foobar" $as_echo_n "foobar"
関数で /bin/zsh
を経由する
初期化を無効にするオプションってあったっけ?
echo(){ /bin/zsh -c "echo \"\${@}\"" -- "${@}" }
printf を使わない場合
改行抑制
OS X の場合 /bin/echo
を使うようにすれば -n
オプションで改行が抑制できる。ただしビルトインに比べると遅い。
/bin/echo -n foo
エスケープ文字
$'string'
による展開を用いる。
echo $'\e[31m'foobar$'\e[m'
テストスクリプトと出力サンプル
- 出力結果を正しく表示するためにはページ幅が 188 以上必要です。
#!/bin/sh # # GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin10.0) # SH=/bin/sh BASH=/bin/bash ZSH=/bin/zsh BSD_ECHO=/bin/echo if test -x "/opt/local/bin/gecho" ; then GNU_ECHO=/opt/local/bin/gecho elif test -x "/usr/local/bin/gecho" ; then GNU_ECHO=/usr/local/bin/gecho else GNU_ECHO=: fi #------------------------------------------------------------------------------- e1()( /bin/cat <<\EOS echo -n ${LINENO} echo -e ${LINENO} echo -E ${LINENO} EOS ) e2()( /bin/cat <<\EOS echo " " echo "\t" echo -e "\t" EOS ) e3()( /bin/cat <<\EOS echo "${LINENO} ${LINENO}" echo "${LINENO}\n${LINENO}" echo -e "${LINENO}\n${LINENO}" EOS ) e4()( /bin/cat <<\EOS echo "${LINENO}\c" echo -e "${LINENO}\c" EOS ) e5()( /bin/cat <<\EOS echo \\e[31m${LINENO}\\e[m echo \\033[31m${LINENO}\\033[m echo \\x1b[31m${LINENO}\\x1b[m echo "\e[31m${LINENO}\e[m" echo "\033[31m${LINENO}\033[m" echo "\x1b[31m${LINENO}\x1b[m" echo -e \\e[31m${LINENO}\\e[m echo -e \\033[31m${LINENO}\\033[m echo -e \\x1b[31m${LINENO}\\x1b[m echo -e "\e[31m${LINENO}\e[m" echo -e "\033[31m${LINENO}\033[m" echo -e "\x1b[31m${LINENO}\x1b[m" EOS ) e6()( /bin/cat <<\EOS echo [31m${LINENO}[m echo "[31m${LINENO}[m" EOS ) e7()( /bin/cat <<\EOS echo $'\e[31m'${LINENO}$'\e[m' echo $'\x1b[31m'${LINENO}$'\x1b[m' echo $'\033[31m'${LINENO}$'\033[m' EOS ) e8()( /bin/cat <<\EOS echo "\uf8ff" LANG=ja_JP.eucJP echo "\uf8ff" LANG=ja_JP.UTF-8 echo "\uf8ff" EOS ) #------------------------------------------------------------------------------- C0=188 C1=34 C2=20 Hr=$(/usr/bin/jot -b = -s "" ${C0}) escape()( /usr/bin/sed -n " s/"$'\e'"\[31m// s/"$'\e'"\[m// s/"$'\t'"/ / l " ) Sh()( echo "${Hr}\n${1}\n${Hr}" \ | /usr/bin/fmt -cw ${C0} \ | /usr/bin/lam -P -${C0} - ) Ss()( ( echo "${1}" /usr/bin/jot -b "-" -s "" ${C2} ) \ | /usr/bin/fmt -cw ${C2} ) #------------------------------------------------------------------------------- for f in e{1..8} do case ${f} in e1) Sh "OPTION" ;; e2) Sh "TAB" ;; e3) Sh "NEWLINE" ;; e4) Sh "SUPPRESS TRAILING NEWLINE" ;; e5) Sh "ESCAPE CHARACTER" ;; e6) Sh "ESCAPE CHARACTER (RAW)" ;; e7) Sh "QUOTE EXPAND" ;; e8) Sh "UNICODE" ;; esac ( Ss "${SH}" ; ${f} | exec -c ${SH} -s | escape ) \ | \ ( ( Ss "${BASH}" ; ${f} | exec -c ${BASH} -s | escape ) \ | \ ( ( Ss "${BASH} (xpg_echo)" ; ( printf "shopt -s xpg_echo;" ; ${f} ) | exec -c ${BASH} -s | escape ) \ | \ ( ( Ss "${ZSH}" ; ${f} | exec -c ${ZSH} -s 2>&1 | escape ) \ | \ ( ( Ss "${ZSH} (bsdecho)" ; ( printf "setopt -s BSDECHO;" ; ${f} ) | exec -c ${ZSH} -s 2>&1 | escape ) \ | \ ( ( Ss "BSD ECHO (${BSD_ECHO})" ; ${f} | /usr/bin/sed "s|^echo|${BSD_ECHO}|" | exec -c ${SH} -s | escape ) \ | \ ( ( Ss "GNU ECHO" ; ${f} | /usr/bin/sed "s|^echo|${GNU_ECHO}|" | exec -c ${SH} -s | escape ) \ | \ ( ( echo "COMMAND" | /usr/bin/fmt -cw ${C1} /usr/bin/jot -b - -s "" ${C1} ${f} \ | /usr/bin/sed "s/"$'\t'"/ /" \ | /bin/cat -v ) \ | \ ( /usr/bin/lam \ -P -${C1}.${C1} /dev/fd/0 \ -P -${C2}.${C2} -S " " /dev/fd/{3..9} ) ) 9<&0 ) 8<&0 ) 7<&0 ) 6<&0 ) 5<&0 ) 4<&0 ) 3<&0 echo done
以下、出力サンプルですが Qiita だと正しく表示されてないかもしれません。
$
は改行文字を表します。<tab>
はスペース8個に変換されています。- COMMAND 列を除き展開された
<esc>
(^[
)と[31m
、[m
は省略されています。
============================================================================================================================================================================================ OPTION ============================================================================================================================================================================================ COMMAND /bin/sh /bin/bash /bin/bash (xpg_echo) /bin/zsh /bin/zsh (bsdecho) BSD ECHO (/bin/echo) GNU ECHO ---------------------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- echo -n ${LINENO} -n 1$ 12$ 12$ 12$ 12$ 1-e 2$ 12$ echo -e ${LINENO} -e 2$ 3$ 3$ 3$ 3$ -E 3$ 3$ echo -E ${LINENO} -E 3$ ============================================================================================================================================================================================ TAB ============================================================================================================================================================================================ COMMAND /bin/sh /bin/bash /bin/bash (xpg_echo) /bin/zsh /bin/zsh (bsdecho) BSD ECHO (/bin/echo) GNU ECHO ---------------------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- echo " " $ $ $ $ $ $ $ echo "\t" $ \t$ $ $ \t$ \t$ \t$ echo -e "\t" -e $ $ $ $ $ -e \t$ $ ============================================================================================================================================================================================ NEWLINE ============================================================================================================================================================================================ COMMAND /bin/sh /bin/bash /bin/bash (xpg_echo) /bin/zsh /bin/zsh (bsdecho) BSD ECHO (/bin/echo) GNU ECHO ---------------------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- echo "${LINENO} 2$ 2$ 2$ 1$ 1$ 2$ 2$ ${LINENO}" 2$ 2$ 2$ 1$ 1$ 2$ 2$ echo "${LINENO}\n${LINENO}" 3$ 3\n3$ 3$ 3$ 3\n3$ 3\n3$ 3\n3$ echo -e "${LINENO}\n${LINENO}" 3$ 4$ 3$ 3$ 4$ -e 4\n4$ 4$ -e 4$ 4$ 4$ 4$ 4$ 4$ 4$ 4$ 4$ ============================================================================================================================================================================================ SUPPRESS TRAILING NEWLINE ============================================================================================================================================================================================ COMMAND /bin/sh /bin/bash /bin/bash (xpg_echo) /bin/zsh /bin/zsh (bsdecho) BSD ECHO (/bin/echo) GNU ECHO ---------------------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- echo "${LINENO}\c" 1-e 2$ 1\c$ 12$ 12$ 1\c$ 1-e 2$ 1\c$ echo -e "${LINENO}\c" 2$ 2$ 2$ ============================================================================================================================================================================================ ESCAPE CHARACTER ============================================================================================================================================================================================ COMMAND /bin/sh /bin/bash /bin/bash (xpg_echo) /bin/zsh /bin/zsh (bsdecho) BSD ECHO (/bin/echo) GNU ECHO ---------------------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- echo \\e[31m${LINENO}\\e[m \e[31m1\e[m$ \e[31m1\e[m$ \e[31m1\e[m$ zsh: bad pattern: \e zsh: bad pattern: \e \e[31m1\e[m$ \e[31m1\e[m$ echo \\033[31m${LINENO}\\033[m 2$ \033[31m2\033[m$ 2$ zsh: bad pattern: \0 zsh: bad pattern: \0 \033[31m2\033[m$ \033[31m2\033[m$ echo \\x1b[31m${LINENO}\\x1b[m 3$ \x1b[31m3\x1b[m$ 3$ zsh: bad pattern: \x zsh: bad pattern: \x \x1b[31m3\x1b[m$ \x1b[31m3\x1b[m$ echo "\e[31m${LINENO}\e[m" \e[31m4\e[m$ \e[31m4\e[m$ \e[31m4\e[m$ 4$ \e[31m4\e[m$ \e[31m4\e[m$ \e[31m4\e[m$ echo "\033[31m${LINENO}\033[m" 5$ \033[31m5\033[m$ 5$ 5$ \033[31m5\033[m$ \033[31m5\033[m$ \033[31m5\033[m$ echo "\x1b[31m${LINENO}\x1b[m" 6$ \x1b[31m6\x1b[m$ 6$ 6$ \x1b[31m6\x1b[m$ \x1b[31m6\x1b[m$ \x1b[31m6\x1b[m$ echo -e \\e[31m${LINENO}\\e[m -e \e[31m7\e[m$ \e[31m7\e[m$ \e[31m7\e[m$ zsh: bad pattern: \e zsh: bad pattern: \e -e \e[31m7\e[m$ 7$ echo -e \\033[31m${LINENO}\\033[m -e 8$ 8$ 8$ zsh: bad pattern: \0 zsh: bad pattern: \0 -e \033[31m8\033[m$ 8$ echo -e \\x1b[31m${LINENO}\\x1b[m -e 9$ 9$ 9$ zsh: bad pattern: \x zsh: bad pattern: \x -e \x1b[31m9\x1b[m$ 9$ echo -e "\e[31m${LINENO}\e[m" -e \e[31m10\e[m$ \e[31m10\e[m$ \e[31m10\e[m$ 10$ 10$ -e \e[31m10\e[m$ 10$ echo -e "\033[31m${LINENO}\033[m" -e 11$ 11$ 11$ 11$ 11$ -e \033[31m11\033[m$ 11$ echo -e "\x1b[31m${LINENO}\x1b[m" -e 12$ 12$ 12$ 12$ 12$ -e \x1b[31m12\x1b[m$ 12$ ============================================================================================================================================================================================ ESCAPE CHARACTER (RAW) ============================================================================================================================================================================================ COMMAND /bin/sh /bin/bash /bin/bash (xpg_echo) /bin/zsh /bin/zsh (bsdecho) BSD ECHO (/bin/echo) GNU ECHO ---------------------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- echo ^[[31m${LINENO}^[[m 1$ 1$ 1$ zsh: bad pattern: ^[ zsh: bad pattern: ^[ 1$ 1$ echo "^[[31m${LINENO}^[[m" 2$ 2$ 2$ 2$ 2$ 2$ 2$ ============================================================================================================================================================================================ QUOTE EXPAND ============================================================================================================================================================================================ COMMAND /bin/sh /bin/bash /bin/bash (xpg_echo) /bin/zsh /bin/zsh (bsdecho) BSD ECHO (/bin/echo) GNU ECHO ---------------------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- echo $'\e[31m'${LINENO}$'\e[m' 1$ 1$ 1$ 1$ 1$ 1$ 1$ echo $'\x1b[31m'${LINENO}$'\x1b[m' 2$ 2$ 2$ 2$ 2$ 2$ 2$ echo $'\033[31m'${LINENO}$'\033[m' 3$ 3$ 3$ 3$ 3$ 3$ 3$ ============================================================================================================================================================================================ UNICODE ============================================================================================================================================================================================ COMMAND /bin/sh /bin/bash /bin/bash (xpg_echo) /bin/zsh /bin/zsh (bsdecho) BSD ECHO (/bin/echo) GNU ECHO ---------------------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- echo "\uf8ff" \uf8ff$ \uf8ff$ \uf8ff$ zsh: character not i \uf8ff$ \uf8ff$ \uf8ff$ LANG=ja_JP.eucJP echo "\uf8ff" \uf8ff$ \uf8ff$ \uf8ff$ $ \uf8ff$ \uf8ff$ \uf8ff$ LANG=ja_JP.UTF-8 echo "\uf8ff" \uf8ff$ \uf8ff$ \uf8ff$ zsh: character not i \uf8ff$ \uf8ff$ \uf8ff$ $ $