Bash基礎文法最速マスター。これはひどい。この手のシェル入門者向けまとめはこれまで何度か見てきたけど、その中でもダントツにひどい。何がひどいって、必要なことがことごとく抜け落ちていて、にもかかわらず「基礎」には必要のないことばかり書かれているということ。_ 冒頭からおかしい。
他の言語をある程度知っている人はこれを読めばBashの基礎をマスターしてBashを書くことができるようになっています。無理。そもそも、他の言語と同じように書こうという発想そのものが間違っている。_ シェルスクリプトというのは各種コマンドをうまい具合に組み合わせて目的を達するために書くものであって、それ単体で複雑な処理やらアルゴリズムを記述するものではない。そういうことが必要ならば、クソな言語仕様の sh なんか捨ててもっとマシなスクリプト言語を使うべきだ。昔ながらの sh では配列が使えないけど bash なら配列が使える。だから bash を使おう、ではなく、配列が必要なほどのデータを管理しなければならないのならばはじめから perl なり ruby なりの言語を使う、あるいは sh でやるにしても自分自身でデータを管理するのではなく外部コマンドのパイプラインにうまく載せて最終結果だけを受け取るように書く。bash の配列を駆使してクイックソートを書いても誰も褒めない。アホがいる、と笑われるだけ。
_ 最低限必要なのは、変数やワイルドカードの展開、パイプラインやリダイレクト、正常終了がゼロでエラーはそれ以外というルール(条件判断の [ ] はカッコではなくコマンドであるという事実)。それにまったく触れないで基礎文法も何もあったもんじゃない。
_ ただの Hello, world です。まだやってんのか。
#!/bin/sh ____=.... _____=..... __=$____$_____ _______=/???/???/??${#_____}??? [ "$_______" = $_______ ] && _______=/????/[^${#_________}-${#__}][^${#_________}-${#__}]${#_____} __=`$_______<<_` __=${__#?????} ________=${__#?} ________=${__%$________} __=${__#???????} ______=${__#?} ______=${__%$______} __=${__#????} ___=${__#?} ___=${__%$___} ______=`/$______??/$___$________?? /$______??/$___$________??` ___________=${______#*$___$________?} __=\\${#_________} _______=$__${#___}${#_____}${#____}$___________ [ "_`$______ -$___ $_______`" = "_-$___ $_______" ] && ______=${______#/???/} || [ "_`$______ $_______`" = "_$_______" ] && ______="$______ -$___" __________=$__${#___}${#_______}${#__} _______=$_______, $______ $__${#___}${#___}${#_________}$___$__${#___}${#_____}${#____}$_______ $__${#___}${#__}${#_______}$___________$__________$__${#___}${#_____}${#____}$__${#___}${#____}${#____}!
- スクリプト名の縛りや ホームディレクトリ位置の縛りはありません
- 動くことを確認
- FreeBSD + { ash, ksh }
- Debian + { dash, bash }
- OpenSolaris + { ksh, bash }
- MacOSX + bash
- 動かないことを確認: zsh
- 確認してないけど動かないはず: OpenSolaris じゃない Solaris、元祖 Bourne sh
- 既知の不具合: ksh -x で実行すると core を吐いて落ちる(-x がなければ問題ない)
_ echo の4文字を得るために、これまでは $0 (スクリプト名)や ~ (ホームディレクトリ)からスタートしていたけど、これらは環境に激しく依存する。記号だけでアルファベットを作るのは困難だけど、数字は ${#var} で簡単に作れるので、数字を含むコマンドをワイルドカードにマッチさせることを考えた。
_ いろんな環境にあって数字を含むコマンドといえば /usr/bin/m4 だけど、記号しか使えなければ m4 では cat 相当のことしかできない。うーんどうしたもんかと半日悩んだ末に md5 を取ることにした。しかし、これ環境に依存する。なんとかがんばって記号文字だけで /usr/bin/md5sum (linux, opensolaris) と /sbin/md5 (freebsd, macosx) を判別させることに成功したが、この時点で zsh (意図しないタイミングでワイルドカードが展開される)と solaris (/usr/bin/md5sum や /sbin/md5 じゃなくて digest -a md5 を使え)が脱落。
_ ここまでできればあとは空文字列の md5 から b,c,e を拾って /b??/ec?? にマッチさせて /bin/echo を作り、 これまでと同じように8進文字コードを echo して完了。せっかくなので各種環境の echo の仕様の違い(シェル内蔵 echo と /bin/echo のどちらを使うか、-e は必要かどうか)も判別させるようにして、かなり環境非依存な Hello, world になった。
_ 以下、アンスコな変数名に置換する前のものにコメントを付加したもの。
s4=.... s5=..... s9=$s4$s5 md5=/???/???/??${#s5}??? [ "$md5" = $md5 ] && md5=/????/[^${#s0}-${#s9}][^${#s0}-${#s9}]${#s5} # /usr/bin/md5sum or /sbin/md5 # /????/??5 でなく /????/[^0-9][^0-9]5 なのは /proc/345 にマッチさせないため sum=`$md5<<_` # 空文字列の md5 (d41d8cd98f00b204e9800998ecf8427e) sum=${sum#?????} # b,c,e を切り出す c=${sum#?} c=${sum%$c} sum=${sum#???????} b=${sum#?} b=${sum%$b} sum=${sum#????} e=${sum#?} e=${sum%$e} echo=`/$b??/$e$c?? /$b??/$e$c??` # /bin/echo をゲット! o=${echo#*$e$c?} # /bin/echo から o を切り出す x=\\${#s0} lo=$x${#e}${#s5}${#s4}$o # 8進文字列を作る (\0154o -> "lo") [ "_`$echo -$e $lo`" = "_-$e $lo" ] && echo=${echo#/???/} || [ "_`$echo $lo`" = "_$lo" ] && echo="$echo -$e" # 各種環境の echo の仕様に合わせて {/bin/,}echo{, -e} のどれを使うか判定 r=$x${#e}${#lo}${#x} # \0162 -> "r" lo=$lo, $echo $x${#e}${#e}${#s0}$e$x${#e}${#s5}${#s4}$lo $x${#e}${#x}${#lo}$o$r$x${#e}${#s5}${#s4}$x${#e}${#s4}${#s4}! # \0110e\0154\0154o, \0127o\0162\0154\0144! -> "Hello, World!"