前から気になってた ShellCheck を使ってシェルスクリプトや.bashrc等直してみました。
ShellCheck
ShellCheck はシェルスクリプトの文法をチェックしてくれるオンラインサービスです。
ShellCheckのページに行って 試したいスクリプトを書き込むと文法をチェックして エラーや注意を表示してくれます。
指摘してくれるものとしては、明らかな文法違反な物は勿論、
実際にスクリプトを回して毎回エラーになるものでなくても、
変数が空の場合に""
で囲ってないとエラーになる場合なども
チェックしてくれるので思わぬ事故も防いでくれます。
コマンドライン版
ShellCheckのソースコードはGitHubで公開されていて、
さらにコマンドライン版のshellcheck
を使うことも出来ます。
MacならHomebrewで一発:
$ brew install shellcheck
LinuxでもDebian系なんかだとapt-get
でインストールが出来ます。
$ apt-get install shellcheck
もしくはCabal を使ってインストールする方法がGitHubのREADMEで紹介されています。
$ cabal update
$ cabal install shellcheck
コマンドライン版の使い方は、
$ shellcheck <file>
でOK。
オプションとしては:
-e CODE1,CODE2..
,--exclude=CODE1,CODE2..
:SC2045
など、shellcheck
が返すエラーコードを指定して、そのエラーや警告を無視する。-f FORMAT
,--format=FORMAt
: 出力フォーマットの指定。tty
: 通常のテキストアウトプット(デフォルト)。gcc
: gccライクなアウトプット。checkstyle
: XML形式。json
: Json形式。
-s SHELL
,--shell=SHELL
:sh
,bash
,ksh
,zsh
を与えてシェルの指定(デフォルトはbash
)。-V
: バージョン情報。-h
: ヘルプ。
取り敢えず
インストール後、.bashrcをshell check .bashrc
で
チェックしてみると
こんな感じでエラーやらが出てきます。
gcc
形式にすると
$ shellcheck -f gcc .bashrc
...
.bashrc:48:20: error: Don't quote rhs of =~, it'll match literally rather than as a regex. [SC2076]
.bashrc:59:13: warning: Quote this to prevent word splitting. [SC2046]
.bashrc:98:9: note: Double quote to prevent globbing and word splitting. [SC2086]
.bashrc:100:11: note: Double quote to prevent globbing and word splitting. [SC2086]
...
こんな感じ。 どんなエラーが多いかと言うことで調べてみると
$ shellcheck -f gcc .bashrc | cut -d' ' -f2-|sort|uniq -c|sort -n
1 error: Double quote array expansions, otherwise they're like $* and break on spaces. [SC2068]
1 note: $/${} is unnecessary on arithmetic variables. [SC2004]
1 note: Shebang (#!) missing. Assuming Bash. [SC2148]
1 note: Use find instead of ls to better handle non-alphanumeric filenames. [SC2012]
1 note: echo won't expand escape sequences. Consider printf. [SC2028]
1 warning: Assigning an array to a string! Assign as array, or use * instead of @ to concatenate. [SC2124]
1 warning: This expands when defined, not when used. Consider escaping. [SC2139]
1 warning: Use "$@" (with quotes) to prevent whitespace problems. [SC2048]
2 error: Aliases can't use positional parameters. Use a function. [SC2142]
2 note: Expressions don't expand in single quotes, use double quotes for that. [SC2016]
2 warning: Don't use variables in the printf format string. Use printf "..%s.." "$foo". [SC2059]
2 warning: Quote this to prevent word splitting. [SC2046]
6 note: Use $(..) instead of deprecated `..` [SC2006]
12 error: Don't quote rhs of =~, it'll match literally rather than as a regex. [SC2076]
39 note: Double quote to prevent globbing and word splitting. [SC2086]
$
こんな出てました。
一番多いのは
In a.sh line 29:
if [ -r $arg ]; then
^-- SC2086: Double quote to prevent globbing and word splitting.
と言った変数をダブルクォートで囲みなさい、とう忠告。
空白を含んでいたりする時に2つに別れて認識されてしまったりするのを回避しないと行けません。
単にecho
してるだけのところとかも指摘されるので、エラーではなくnote
になってますが、
一応気をつけてるつもりですが結構空白があり得る所にも残ってました。。。
次に多かったのはエラーで
In .bashrc line 48:
if [[ "$OSTYPE" =~ "darwin" ]];then
^-- SC2076: Don't quote rhs of =~, it'll match literally rather than as a regex.
と言った、=~
を使った場面での右辺をクォートしてしまっている所。
この手の式は大概左辺に右辺の文字列を含んでいたら、的な意味合いで使っていますが、
右辺には正規表現を使うことが出来るので、正規表現を使った時に
思ってるのと違う様になるよ、ということ。
.bashrcの中で使ってるのは正規表現を使ったものは
無いのでどちらでも一緒ですが、正しく使うためにクォートを外しました。
他には``
で囲って式の値を取るのではなく、
$()
を使いなさい、といったものや、
printf
の引数の中では直接変数を使わずに%s
等を使ってフォーマット形式にしなさいとか
$(())
の中では変数に$
とか要らないとか、
引数全部を文字列として一括で渡す時に$@
としてでなく$*
で渡せとか
1
。。。
他のエラーとかも説明に従って直していけば簡単に直していけると思います。
色々とチェックをしてくれますが、 About ShellCheck にはチェックされる項目の一部が載っています。
In a.sh line 257:
alias hischeck="history|awk '{print \$4}'|sort|uniq -c|sort -n"
^-- SC2142: Aliases can't use positional parameters. Use a function.
と言ったエラーもでましたが、これはawk
の中で使ってる$4
が
alias
にしてるコマンド自身に渡す引数と勘違いされてます。
これを今後チェックする時に避けてもらうためには-e SC2141
をshellcheck
に渡してしまっても良いのですが、これだと他で実際このエラーが有るときも無視してしまいます。
この部分だけ無視するには、この行の直前に
# shellcheck disable=SC2142
alias hischeck="history|awk '{print \$4}'|sort|uniq -c|sort -n"
の様に、shellcheck disable=~
というコメント行を加えます。
複数無視したい場合はdisable
を複数書くか、disable=SC2142,SC2143
の様にコンマでつなげても行ける様です。
日本語を含んだファイル
日本語を含んだファイルなんかをチェックしようとすると
shellcheck: user error (Text.Regex.Posix.String died: (ReturnCode 17,"illegal byte sequence"))
と言ったエラーが出てチェックできないので、 どうしてもやりたい場合には一時的にその部分だけコメントアウトするなり 日本語以外の部分だけコピーしてチェックするなりする必要があります。
Vimでは
Vimでは
syntasticプラグインが入っていれば、
shellcheck
をインストールした段階で自動的にシェルスクリプトの編集時には
Syntastic
でshellcheck
を使うようになってより強力にチェック出来るので、
vim
+Syntastic
を使ってる場合には、
shellcheck
をコマンドラインで使わなくても取り敢えず入れておくと便利です。
-
val="$@"
と
val="$*"
は同じ物ですが、
val=("$@")
と
val=("$*")
では、前者は配列としとして
$1
,$2
…が順に入りますが、 後者は$1 $2...
と全てが連結した文字列が配列の0番目に入ります。なので普通に
val="$@"
とやる分には別に問題は無いと思いますが、 その辺きちんと理解しときなさい、と言う意味でwarning
を出してる感じだと思います。