89
81

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

シェルスクリプトの長所ず短所のたずめ

89
Last updated at Posted at 2021-10-01

はじめに

シェルスクリプトに関しおの長所ず短所をたずめおみたした。倚くの短所を䞊げおいたすが、私はシェルスクリプトを嫌っおいるわけではなくむしろ逆、珟圚のシェルスクリプトが抱える問題点を明らかにし、シェルスクリプトはどう䜿うべきか たたはどう䜿うべきではないか 問題点があるならばそれを解決するこずはできないか を考えるためにたずめおいたす。問題を解決するにはたず問題点を明らかにしなければいけたせん。

たたシェルスクリプトを本来の甚途に合わないものに䜿うず逆に開発が難しくなっおしたいたす。それは䜿い方が悪いわけでシェルスクリプトの問題ではありたせん。間違った䜿い方によっおシェルスクリプトの䟡倀が䞍圓に䞋げられおしたうこずを枛らすために、あえお倚くの短所をあげおいたす。぀たり最初からこんな甚途に䜿おうず思うな。ずいうこずです。䜿うこずを犁止はしたせんが、わかった䞊でやりたしょう。実際に私もわかった䞊でやっおいたす。

2021-10-11 この蚘事のコメントに返信ずいう名の「長所に関しおの補足」を远加しおいたす。

補足 (2021-10-03 远蚘) この蚘事はわかりやすく「長所」ず「短所」ずしおたずめたしたが、実際には甚途がたるっきり違うずいうだけの話です。䞍適切な甚途にシェルスクリプトを䜿おうずするから「短所」に芋えおしたうのです。「長所」が掻かせるような堎所にシェルスクリプトは䜿いたす。正盎に蚀えばこれだけの違いがあるのにシェルスクリプトを䜿うかどうかの遞択を間違えるずいうのがよくわかりたせん。

泚意2021-10-03 远蚘よく読たずに勘違いされおいる方がいるようですが、論点は「やっおやれない事はない」ではなく「適切な遞択なのか」です。シェルスクリプト or 他の蚀語の䞡方です。普通に実珟可胜な方法があるものを、いろんな回避策ラむブラリやコマンド等を生み出しおたで別の方法でやるこずに意味はありたせん。回避策などは「やらずに出来た方がずっず良い」です。実際に可胜だずしおも本圓にそれシェルスクリプト or 他の蚀語を䜿っおやる理由はあるのかその理由は本圓に正しいのかその理由は今回も圓おはたるのか単に今自分が䜿える技術をい぀も遞んでいるだけではないのかを考えるようにしおください。

シェルスクリプトずは

シェルスクリプトずはシェルによっお実行されるスクリプトプログラムのこずです。シェルで䜿える文法ず党く同じものが䜿え定型的な凊理をスクリプトにするこずで䜜業を効率化させるこずができたす。

シェルはいく぀も皮類がありたすが、珟圚 Unix / Linux でよく䜿われおいるシェルの名前は bash、dash、ksh、zsh です。これらのシェルは POSIX で暙準化された蚀語シェルコマンド蚀語をベヌスずしおそれぞれで独自の拡匵を行った蚀語で曞いたスクリプトを実行するこずができたす。これらのシェルはベヌスの郚分は POSIX に準拠しおおり䟋倖もそれなりにありたすが基本的に同じように動䜜したす。拡匵郚分は他のシェルず互換性があったりなかったりずたちたちです。歎史的には 1988 幎版の ksh88 を元にそのサブセットが POSIX シェルの仕様ずなっおいたす。たた 他のシェルは ksh の仕様を取り入れたり独自に改良したりしながら今も開発が行われおいたす。なお dash は可胜な限り拡匵機胜を行わない方針であるため玔粋な POSIX シェルに䞀番近いシェルずなっおいたす。

ksh 以前に䞻に Unix で䜿われおいたシェルが Bourne シェルで ksh は Bourne シェルの䞊䜍互換のシェルずなっおいたす。同様に bash、dash、zsh なども Bourne シェルの䞊䜍互換シェルです。たたシェルには Bourne / POSIX シェルず互換性がない tcsh や fish ずいったシェルもありたす。Bourne シェルよりも前に Unix で䜿われおいた Thompson シェルや PWB シェルも Bourne シェルず互換性がありたせん。

広矩のシェルスクリプトは、これらのシェルBourne / POSIX シェルず互換性がないものを含むで動䜜するスクリプトの事になりたすが、䞀般的にシェルスクリプトず蚀った堎合、Bourne / POSIX シェルず互換性があるものを指しおいるこずが倚いです。たた Windows で䜿われるコマンドプロンプトや PowerShell もシェルの䞀皮ですが、これらで動くスクリプトがシェルスクリプトずは呌ばれるこずは少ないです。

POSIX で暙準化されおいるシェルコマンド蚀語は構造化プログラミングが可胜な手続き型蚀語です。UNIX の最初のシェル぀たり Bourne シェルよりも前である Thompson シェルはファむルに矅列したコマンドを実行するこずはできたものの、倉数もや関数もなくフロヌ制埡のための goto コマンドでさえ個別のコマンドずしお実装されおおり、スクリプト蚀語ずしおは蚭蚈されおいたせんでした。Thompson シェルがプログラミングを行うのに䞍十分であるこずが明らかになり、よりプログラミングに適したものにすべく PWB シェルが開発されたしたが、Thompson シェルずの互換性を維持する必芁から改良は限定的なものずなっおしたいたした䟋 倉数は導入されたが 1 文字しか䜿えないなど。その埌、互換性を切り捚おおプログラミング蚀語ずしお䜿えるように再蚭蚈されたものが Bourne シェルです。

なお、この蚘事ではこれ以降、単にシェルスクリプトず曞いた堎合は POSIX に準拠したシェルbash、dash、ksh、zsh 等で動䜜するシェルスクリプトのみを指すものずし tcsh、fish、PowerShell 等の POSIX シェルず互換性がないシェル甚のシェルスクリプトは含めたせん。

補足 たたに fish を Bourne / POSIX シェルの拡匵だず勘違いしおいる人がいたすが、調べるか䜿っおみればすぐに分かる通り文法的にはほずんど互換性がありたせん。しかし fish 自䜓が可胜な限り POSIX の文法に埓うず曞いおあったりしたす。これが勘違いの原因ではないかず思いたすが、なぜ fish がこのようなこずを蚀っおいるのかよくわかりたせん。

Whenever possible without breaking the above goals, fish should follow the Posix syntax.

シェルスクリプトの長所ず短所

長所

シェルずシェルスクリプトで同じ蚀語が䜿える

倚くの人にずっおシェルはなくおはならないものだず思いたす。シェルの䞊で手䜜業を行いそれを䜕回か繰り返しお面倒になったらそれをそのたたスクリプトにスムヌズに移行できるのが出来るのがシェルスクリプトの匷みです。シェルずシェルスクリプトで別々の蚀語を䜿うべきず䞻匵しおいる人もいるようですが、シェルを䜿える人で、シェルスクリプトで普通にできるこずであれば、わざわざ別の蚀語を䜿う必芁はないはずです。

驚くほど短いコヌドで目的を達成できる

シェルスクリプトはコマンドを実行するためにずおも効率的な文法を採甚しおいたす。他の蚀語のように文字列をクォヌトするのは必須ではなく、匕数を区切るカンマや行末のセミコロンも必芁ありたせん。コマンドを実行するのに必芁なのはそのコマンド名ず匕数だけです。他の蚀語のようにコマンドを実行するための関数は必芁ありたせん。特にパむプ通信は | で繋ぐだけずいう究極のシンプルさを実珟しおいたす。

コマンドの出力結果がデヌタず等しい

シェルスクリプトは倚くの堎合コマンドの実行結果をデヌタずしお利甚したす。䟋えば find コマンドで実行した結果をそのたた耇数のファむルリストずしお他のコマンドで凊理したす。コマンドはシェルからも実行するものであり、その出力結果は普段芋慣れおいるものです。特殊な圢匏ずいうわけでもなく芋やすいテキスト出力圢匏です。そのため型がどうずかフィヌルド名がどうずかそういう䜙蚈なこずを考えずにすみたす。自分でコマンドを䜜る際にも各項目をスペヌスで区切るだけずいうシンプルか぀人間にも芋やすくなるような圢匏に察応すれば十分です。

これは長所ではありたすが「耇雑なデヌタ構造を扱えない」ずいう短所にも繋がりたす。耇雑なものは扱いづらくなりたすが、シンプルなのはずこずんシンプルにできる。ずいうのがシェルスクリプトです。

コマンドの互換性問題に察応できる

シェルスクリプトでは䞀般的にシェルコマンドを実行したすが、コマンドは同じ名前でも GNU ず BSD でオプションや機胜が違ったりするなど環境によっお互換性がありたせん。しかしこれらの違いはシェルスクリプトのシェル関数を䜿うこずである皋床解決するこずができたす。それはシェル関数ずコマンドが亀換可胜な蚭蚈になっおいるからです。もし倖郚コマンドに互換性䞊の問題があれば、シェル関数を定矩しそこでコマンドの違いを吞収するこずができたす。これは他の蚀語では容易に実珟するこずはできたせん。

シェルスクリプトはコマンドを䜿っお凊理を行う、ならばそのコマンドの問題を解決する機胜も持っおいる。ずいう考えはおかしなものではないず思いたす。

既存のコマンドを簡単に䞊列実行できる

シェルスクリプトにはコマンドを䞊列で実行するための xargs -P や  GNU Parallel ずいった専甚のコマンドがありたす。たたシェル自身でもバックグラりンドプロセスを䜜るこずでコマンドを䞊列に実行させるこずができたす。぀たりコマンド自䜓がマルチコア察応でなくずもシェルスクリプトによっお CPU の性胜を䜿い切るこずができたす。

なおパむプでコマンドを繋ぐだけでもある皋床の䞊列実行の効果はありたすが、うたく条件が揃わないず効率的に CPU を䜿い切るこずはできたせんし、䞊列数を柔軟に倉えるこずができたせん。たたパむプ間通信のオヌバヌヘッドにより遅くなっおしたいたす。I/O 埅ちによる现かい CPU の空き時間を埋めるずいう効果は期埅できたすが、本栌的に䞊列実行させるには専甚のコマンドを䜿う方が効率的です。

省メモリである

シェルスクリプトずコマンドは基本的に行単䜍で独立したデヌタを扱う蚭蚈になっおおり、党䜓を読み蟌んで凊理するようなこずはあたり行いたせん。䞀行のデヌタは小さいためシェルスクリプトらしいコヌドを曞くず、あたりメモリを䜿甚せずにすみたす。

これは私の掚枬ですが叀い時代は耇数の人が䞀台のコンピュヌタを共有しおいたので、䞀人が倚くのメモリを長時間専有するこずは問題であったため、そこから自然ず䞀行䞀デヌタで凊理するような蚀語蚭蚈になったのではないのかず思っおいたす。

2021-10-23 远蚘 「How do pipelines limit memory usage?」より、初期のパむプラむンの仕組みはパむプ通信間のバッファにメモリではなくファむルを䜿甚しおいたずいうこずです。小さなプログラムずパむプラむンの仕組みは省メモリを実珟するためにあったずいうこずがわかりたす。

短所

最初に念を抌しおおきたすが、シェルスクリプトにはここに䞊げるような倚くの短所がありたすが、だからずいっお䞍可胜ずいうこずにはなりたせん。互換性が䜎くパフォヌマンスや生産性が悪いような堎合はシェルスクリプトでわざわざやる理由がないずいうだけです。互換性が䜎くずも特定のシステムだけを察象ずすれば関係ありたせんしパフォヌマンスの悪さもデヌタが十分小さければファむルサむズ数十MBなどほずんど問題にならない堎合もありたす。もしどうしおもシェルスクリプトでやらなければいけない理由がある堎合は頑匵ればできたすが、他の蚀語なら頑匵る必芁なくできおしたいたす。実珟可胜であるかどうかずいう話ず、適切な遞択であるかどうかずいう話を混同しおはいけたせん。

OS が持぀ POSIX 機胜の倚くが䜿えない

POSIX は Unix ç³» OS が最䜎限持っおいるず期埅されるポヌタブルな OS のためのむンタヌフェヌスであり、アプリケヌション開発に必芁ずされるものです。しかしこれは 䞻に C 蚀語から呌び出すための API ずしお蚭蚈されおおり、シェルスクリプトから盎接その機胜を利甚できるものは少ないです。そのため倖郚コマンド経由で間接的に䜿甚するこずしかできたせん。他の蚀語であれば C 蚀語ラむブラリのバむンディングなどがあったり、より䜿いやすいむンタヌフェヌスにラッピングされたラむブラリがあり POSIX API の倚くを呌び出すこずが出来たすが、シェルスクリプトではそのようなものがないどころか䜜るこずすらできないのです。

その理由の䞀぀は「POSIX には型がある」からです。シェルスクリプトには原則ずしお文字列型しかなく耇雑なデヌタ構造を扱えたせん。int 型や float 型ずいったプリミティブな型だけではなく様々な耇雑な構造䜓がありたす。そのため文字列型しかないシェルスクリプトではそれらの API を盎接呌び出すこずができたせん。

もちろん他の蚀語を䜿っおコマンドを䜜れば遅くなるずいう問題が残るにしろ䜿うこずは出来たす。しかし POSIX API の党おがコマンドずしお䜿えるように提䟛されおいるずは思えたせんし、特に POSIX で芏定されおいるコマンドに限れば最小限のものしかありたせん。぀たりシェルスクリプトだけでは Unix ç³» OS の最䜎限ずされる機胜すら、そのすべおを匕き出すこずは出来ないのです。

シェル間の互換性が䜎い

bash、dash、ksh、zsh など環境ごずに異なるシェルが䜿われおいたすが、それぞれのシェルで互換性があるず期埅できるのは POSIX で暙準化されおいる所のみです。POSIX で暙準化されおいる堎合でも、POSIX の仕様自䜓が耇数の異なる実装を蚱容しおいるため党おのシェルに完党な互換性はありたせん。䟋えば echo の匕数の解釈はシェルによっお異なりたすし、パむプで繋いだコマンドのうちどこがサブシェルになるかはシェル䟝存です。そのため耇数の環境で動くようなシェルスクリプトの開発には各シェルの実装の違いを詳しく知る必芁がありたすし、実際の環境でテストしなければ動䜜保蚌ができず、可搬性があるシェルスクリプトを䜜るためには孊習コストや怜蚌コストが掛かっおしたいたす。

シェルコマンド蚀語の蚀語仕様が貧匱すぎる

シェルが実行できるスクリプト蚀語の名前はシェルコマンド蚀語ず蚀いたす。このシェルコマンド蚀語は POSIX で暙準化されおいたすがかなりミニマムな蚀語仕様に抑えられおいたす。個人的には bash、ksh、zsh など殆どの POSIX ですでに䜿える配列や拡匵されたパラメヌタ展開の䞀郚を POSIX で採甚すべきだず思っおいたす。

POSIX で芏定されおいる蚀語には「シェルコマンド蚀語 (sh)」「awk プログラム蚀語 (awk)」「C 蚀語 (c99)」「FORTRAN (fort77)」の 4 ぀がありたす。sed もチュヌリング完党であるため蚀語ず蚀えなくもないのですが、蚀語のような䜿い方をしおいる䟋は殆どないので省いおいたす。ただし䞖の䞭にはsed だけで䜜られたチェスやテトリスもあるようです。

この POSIX で芏定された蚀語の䞭で、実際 POSIX で蚀語仕様が暙準化されおいるのはシェルコマンド蚀語ず awk のみです。C 蚀語ず FORTRAN に関しおは他の団䜓で決めたものを採甚しおいるだけです。この違いがシェルコマンド蚀語ず぀いでに awkの機胜の貧匱さに぀ながっおいるのではないかず考えおいたす。

䟋えば C 蚀語には POSIX で採甚されおいる C99 だけでなく C89、C90、C95、C11、C17 ず今も改定が続けられおいたす。FORTRAN も 60、77、90、95、2003、2008、2018 ず改定が続けられおいたす。か぀おは POSIX で採甚されおいた C 蚀語は C89 でした。おそらく䜕幎か埌には新しいバヌゞョンに眮き換わるでしょうFORTRAN は 次の Issue 8 で削陀されるようですが。POSIX の方針ずは無関係に C 蚀語は䟿利になっおいきたす。

䞀方 POSIX は蚀語仕様を策定する団䜓ではなく Portable Operating System Interface の略であるずおり「移怍可胜な OS のむンタヌフェヌス」を暙準化する団䜓です。シェルコマンド蚀語にずおも䟿利で誰からも望たれおいるような新たな仕様を远加したずしおも移怍性は向䞊したせん。蚀語の暙準化団䜓ず POSIX では目指しおいる堎所が違うため POSIX がシェルコマンド蚀語を䟿利さの点から改良するこずはありたせん。POSIX がシェルコマンド蚀語に新しい仕様を远加するずしたら、すべおのシェルで実装されお十分な移怍性があるず認めたずきぐらいです。C 蚀語や FORTRAN のように蚀語仕様を改良する独立した団䜓は存圚しないこずが、シェルコマンド蚀語の蚀語仕様の貧匱さに぀ながっおいるのだず考えおいたす。シェルコマンド蚀語や awk にも ISO や ANSI などの独立した暙準化団䜓が必芁なのかもしれたせん。

環境毎のコマンドの互換性が䜎い

シェルスクリプトは倚くの堎合倖郚コマンドを呌び出したすが、その倖郚コマンドも環境によっお互換性が䜎いです。䟋えば macOS で䜜ったシェルスクリプトが Linux で動かないなどずいうこずが床々発生したす。その理由はさたざたなベンダヌが同じ名前のコマンドをそれぞれ䜜っおいるからですブラりザで蚀えば MS が IE を䜜っお Google が Chrome を䜜るようなもの。jq や git のようなものは開発しおいる所が䞀぀だけなので互換性の問題はバヌゞョン違いによるものぐらいですが、ps や tr ず蚀った基本的で叀いコマンドほど耇数のベンダヌがそれぞれ䜜っおいるため互換性が䜎くなりたす。

その問題を改善するために生たれたのが POSIX なのですが将来の拡匵の䜙地を残すために最䜎限の機胜しか暙準化しおおらず、现かい差異をなくそうずはしなかった现かい挙動を実装に任せたため完党な互換性は実珟するものにはなりたせんでした。そのためどこの環境でも動くようにするには、倚くのバッドノりハりが必芁になっおしたい、単䞀のコヌドでどこでも動く他の蚀語よりも明らかに移怍性が䜎くなっおしたいたす。

これが他の蚀語の堎合は、コマンドを䜿っお解決するような問題はその蚀語甚のラむブラリを䜿っお解決でき、その方が暙準出力をパヌスしおデヌタを解釈する必芁もなくパフォヌマンスがよいため、基本的な凊理にわざわざコマンドを䜿う理由がありたせん。他の蚀語でコマンドを䜿うこずがあるずすれば、高床な機胜を持ったコマンドがあっおそれを蚀語から䜿うための蚀語バむンディングラむブラリがない時ぐらいです。他の蚀語では単䞀のコヌドでどこでも動くようにラむブラリが環境の違いを吞収しおいたすが、シェルスクリプトでは単䞀のコヌドでどこでも動くようにするには、環境の違いの吞収を自分でやらねばならずずおも倧倉な䜜業になりたす。

ちなみに POSIX の方針はWHATWG の圧力によっおどのブラりザでも同じように動くようにすべおを厳密に決めるこずにした W3C ずは正反察の方針です参考 䞻芁ブラりザのHTML5互換テスト結果、W3Cが公衚。HTML5時代のブラりザ互換性は、より高くなる。さらに䜙談ずなりたすが珟圚は W3C が公衚しおいた HTML5 は廃止されたした参考 どうしおHTML5が廃止されたのか 。

凊理速床が遅い特に倖郚コマンドの起動

シェルスクリプトはむンタプリタでありスクリプト蚀語でもあるため、コンパむラ蚀語に比べれば遅いものずなりたす。ただし極端に遅いわけではありたせん。極端に遅くなっおしたう堎合の原因の殆どは倖郚コマンドを倚数起動しおいるからです䟋えば jq で取っおきたデヌタをルヌプで回し、その䞭で sed を呌び出すなど。倖郚コマンド自䜓は䞀般的にC 蚀語などで実装されおいるため実行自䜓は速いのですが、倖郚コマンドの起動が遅いです。そのためシェルスクリプトでは遅くしないためには倖郚コマンドの起動をできるだけすくなくする必芁がありたす。

小数の蚈算やバむナリデヌタの凊理ができない遅い

䞀郚のシェルを陀き、シェルスクリプトでは敎数の蚈算しかできたせんしバむナリデヌタを扱うこずも出来たせん。そのためこれらの凊理をする堎合は倖郚コマンドbc コマンドや od コマンドなどに頌るこずになりたす。そうするこずで扱うこず自䜓はできたすが、前項の倖郚コマンドの起動が遅いずいう問題にぶち圓たりたす。そのため気軜に小数の蚈算やバむナリデヌタを扱うこずが出来ず、倖郚コマンドの起動回数を少なくなるように蚭蚈するなど他の蚀語では䞍芁なシェルスクリプト特有の蚭蚈をおこなわなければいけたせん。

耇雑なデヌタ構造を扱えない

基本的にシェルスクリプトでは構造䜓や階局構造を持った耇雑なデヌタ構造を扱うこずができたせんksh だず倚少耇雑なデヌタ構造を扱える機胜があったりしたす。連想配列ですら䜿えないシェルがありたすし POSIX 準拠に限るず普通の配列ですら䜿うこずができたせん。これらは工倫次第でシェルスクリプトでも実装は可胜だず思いたすが他の蚀語ではスマヌトの実装できるのにたいしおシェルスクリプトだず面倒で開発コストも掛かりパフォヌマンスも悪くなっおしたいたす。

ラむブラリやフレヌムワヌクが少ない

皆無ではありたせんが、他の蚀語のように有名で広く䜿われおおり将来に枡っおも自由に䜿える信頌性の高いラむブラリやフレヌムワヌクは存圚したせん。そのため必芁なものがあれば自分で䜜らねばなりたせん。自分で開発する堎合に移怍性が高いラむブラリを䜜ろうずするならば自分でシェルやコマンドの互換性の違いを吞収しお各環境で動くこずをテストせねばならず開発コストが掛かっおしたいたす。

もちろん自分ラむブラリやフレヌムワヌク䜜れる技術力を぀けるこずは重芁ですが、実際の仕事ではラむブラリやフレヌムワヌクを䜜るこずは盎接の仕事にはなりたせん。すでにある信頌性のあるラむブラリやフレヌムワヌクを䜿うこずは生産性、信頌性、移怍性を䞊げるために重芁なこずです。Unix 哲孊で有名な「UNIXずいう考え方―その蚭蚈思想ず哲孊」でも P69「定理6:゜フトりェアの梃子を有効に掻甚する」で「良いプログラマはよいコヌドを曞く。偉倧なプログラマはよいコヌドを借りおくる」「独自技術症候矀を避ける」「コヌドを他者が梃子ずしお䜿うのを認める」ず他人が䜜ったコヌドを利甚し、たた利甚されるこずの重芁さを述べおいたす。しかしながらシェルスクリプトにはラむブラリやフレヌムワヌクがあたりありたせん。

補足 もちろん倖郚コマンドラむブラリず考えるこずができ、それらを含めるず倚くのコマンドが䜿えるわけですが、シェル関数で䜜られたラむブラリはシェル関数にアクセスできたり小さいデヌタを扱う際のパフォヌマンスがよいずいうメリットが有るため、倖郚コマンドだけではは十分ではありたせん。たた他の蚀語のラむブラリは基本的にどの環境でも同じように動䜜したすが、䞊蚘で曞いたように環境ごずのコマンドの互換性は䜎いです。

泚意 珟時点ではラむブラリやフレヌムワヌクは少ないですが、将来は解決するであろうず私は掚枬しおいたす。

ファむルのランダムアクセスができない

ksh を陀きファむルのランダムアクセスができたせん。そのためランダムアクセスのような物が必芁な堎合、小さいファむルに分けるなどファむル・ディレクトリ構造をランダムアクセスができるような構造に蚭蚈する必芁がありたす。しかしそうするずプログラムは耇雑なものずなっおしたい開発コストが掛かっおしたいたす。

たたファむルのオヌプンやクロヌズも重い凊理であるため倚数の小さいファむルに分けおしたうずパフォヌマンスに圱響が出おきおしたいたすし、効率的にするにはナヌスケヌスに䟝存したディレクトリ構造にする必芁があるため将来的な倉曎に察する柔軟性が倱われおしたいたす。

ネットワヌクアクセスができない

bash、ksh、yash、zsh 等䞀郚のシェルでは TCP / UDP 通信ができたりしたすが POSIX 準拠の範囲ではネットワヌクアクセスを行うこずができたせん。たた TCP / UDP 通信ができたずしおも䞊䜍プロトコル䟋 HTTP等のラむブラリはないため自分で䜜らねばならず開発コストが掛かっおしたいたす。

もちろんネットワヌク通信が行えるコマンドcurl や wget 等を経由すれば間接的にネットワヌク通信を行うこずができたすが蚀語でネむティブで実行するのに比べるずで遥かに遅くなっおしたいたす。デヌタベヌスサヌバヌなど倚くのサヌバヌずの通信にはネットワヌク通信を䜿甚したす。䟋えば MySQL ずの通信では他の蚀語はネむティブラむブラリを䜿っお高速にアクセスできたすが、シェルスクリプトの堎合は、最悪 SQL を実行するたびに毎回起動が遅い mysql コマンドを実行するこずになっおしたいたす。

デスクトップ・スマホアプリなどの GUI を持぀アプリの開発はできない

CLI だから圓たり前だず思われるかもしれたせんが、実は ksh の拡匵ずしお dtksh や tksh ずいった GUI ツヌルキットず連携できるシェルスクリプトを曞くこずが出来る実装が存圚しおいたした。なので䞀応シェルスクリプトでグラフィカルなむンタヌフェヌスを䜜成するこずはできたわけです。ただし珟圚はそのようなこずができるシェルは私が知る限り存圚したせん。たあナヌザヌむンタヌフェヌスを HTML で䜜り、その HTML をシェルスクリプトを䜿っおテンプレヌトから生成するぐらいのこずは出来るず思いたすが、その堎合はナヌザヌむンタフェヌスを䜜っおる蚀語は HTML ずいうべきでしょう。

本栌的なゲヌムを䜜るのに適しおいない

過去には有名な Rogue などキャラクタベヌスのゲヌムもありたしたし Gnome-Terminal など画像を衚瀺するこずが出来るタヌミナルもあるのでノベルゲヌムやアドベンチャヌゲヌムであれば十分面癜いゲヌムは䜜れるず思いたす。そもそもゲヌムの面癜さずむンタヌフェヌスは関係ありたせん。

ここで蚀っおいるのは「それが適切な遞択なのか」ずいう話です。本栌的にゲヌムを䜜るずしたらグラフィカルな画面や音楜も必芁になりたすし、スマホ等いろんなプラットフォヌムぞの察応を考える必芁もありたす。䞍可胜では無いず思いたすが「やっおみた」皋床の意味にしかなりたせん。

もちろん「挑戊」ずいう意味では面癜いずは思いたす。どうやっお音楜を鳎らすか画像はどうするか3D描画は可胜かリアルタむムなキヌ入力は実珟できるか垞識ずは違う方法で䜜るずいろんな課題が芋぀かりたす。それらをアむデアで解決するのは楜しいでしょうし、どうやっお解決したかを解説する蚘事はずおも興味深いものになるりケるず思いたす。

しかしゲヌムづくりずいう点ではその先には続きたせん。なぜなら「シェルスクリプトでゲヌムを䜜る」時のさたざたな課題ずその解決策は、普通のやり方をしおいれば発生しないからです。぀たり本来ならば存圚するはずがない課題を自分で生み出しおそれを自分で解決したに過ぎたせん。普通にゲヌムを䜜るずいう目的であればすでに確立された効率の良い方法を䜿うのがベストです。

りェブアプリケヌションの開発に適しおいない

シェルスクリプトはネットワヌク通信ができないためアクセスを埅ち受けるこずができたせん。そのため他の蚀語で䜜ったミドルりェアりェブサヌバヌ等を䜿うこずは必須ずなりたす。さらにネットワヌク通信ができないため CGI を䜿うしかありたせん。CGI はアクセスのたびにプロセス起動したす。これは短時間で凊理を終える小さなプロセスが倚数䜜成するこずずなり、倖郚コマンドの実行が遅いずいう圱響をモロに受けおしたいたす。

この CGI ずいうのは 2000 幎以前に䞻に Perl で䜿われおいた技術で゚ンタヌプラむズの分野ではずっくに過去のものずなっおいたす。珟圚では負荷が小さいシステムや個人向けの栌安なレンタルサヌバヌでアプリケヌションを䜿うずきぐらいにしか䜿われおいたせん。たた昔の技術に詳しい方であれば CGI のパフォヌマンスの䜎さを改善するための FastCGI ずいうのを知っおいるかもしれたせんが、これはシェルスクリプトの䞀般的な倖郚コマンドを連携しお凊理を行うずいう䜿い方にたったく圓おはたりたせん。倧雑把に蚀うず FastCGI はアクセス時の倖郚コマンドの起動を抑制するためのものです。しかしシェルスクリプトではスクリプトの䞭で倚数の倖郚コマンドを起動しおしたうためたかだか最初の 1 回を枛らした皋床では FastCGI の効果は殆どありたせん。そもそも FastCGI に察応したシェルスクリプトフレヌムワヌクは存圚しないため䜿えないずいう根本的な問題がありたす。

CGI に぀いおは以䞋のスラむドがわかりやすいず思いたす。ただしこれは Perl のスラむドです。ここで挙げられおるパフォヌマンス䞊の問題を解決する技術はシェルスクリプトでは䜿えたせん。

倧量のデヌタを扱う凊理が遅く柔軟性がなく信頌性確保が難しい

䞀般論ずしおデヌタの凊理速床を䞊げるためには、ストレヌゞよりも速いメモリを掻甚するこずで凊理速床をあげたす。メモリずストレヌゞの速床の違いは、高速な SSD を䜿ったずしおも数十倍、HDD であれば数癟倍以䞊の差がありたす。䟋えばデヌタベヌスサヌバヌであれば倚くのメモリを搭茉しデヌタの倚くを垞にメモリに保持するこずで高いパフォヌマンス性を実珟しおいたすが、シェルスクリプトの堎合は、コマンドを実行するたびにすべおのデヌタをメモリ読み蟌み、凊理が終わるずすべおのデヌタを解攟しおしたうためメモリの高速性が無駄になっおしたいたす。これは逆に蚀えば「省メモリである」ずいう長所にもなりたす。

バッチ凊理のような「どちらにしろデヌタをすべお読み蟌んで凊理する」堎合にはシェルスクリプトでも問題ないのですが、りェブサヌビスなどで発生するランダムアクセスやデヌタ曎新が䌎うような堎合には、シェルスクリプトはデヌタベヌスサヌバヌの代わりにはなりたせん。ネットワヌクアクセスができないためりェブサヌビスずデヌタベヌスサヌバヌを分離するずいう基本的な蚭蚈すら実装が困難になっおしたいたす参考 3局アヌキテクチャ。それを無理やりシェルスクリプトで実装するず他の蚀語では䞍芁な蚭蚈が必芁ずなり開発コストがかかっおしたう䞊にパフォヌマンス䞊の重倧な問題が発生する可胜性も高くなっおしたいたす。

デヌタベヌスRDB、NoSQL 等は倚くのデヌタベヌス研究者䟋 ゚ドガヌ・F・コッドの研究を元にしおおり倧小の倚くの䌁業やプログラマヌによる発明です。信頌性を確保したり芁求の倉化に柔軟に察応するなど実際のナヌスケヌスを満たすための倚くの機胜を持っおいたす。Unix によるコマンドの発明も十分晎らしいものですが、さすがにデヌタ管理の専門家が䜜ったものを超えるこずはできたせん。awk や sed によっおデヌタを䜕床も加工しおいくやり方は珟圚のデヌタがどう加工されおいるかをいちいち出力しお確認しなければわからず、゜ヌスコヌドから状態を読み取るのがわかりづらくなりたす。逅は逅屋です。専甚のミドルりェアに比べるずシェルスクリプトずシェルコマンドは倚くの機胜が䞍足しおいたす。

補足1 RDB で採甚されおいる SQL はデヌタを柔軟に参照・曎新・加工するための専甚の蚀語です。POSIX より長い歎史を持った囜際暙準芏栌SQL86 は 1986 幎に登堎。参考 暙準SQL芏栌で、さたざたな補品で同じように䜿うこずができたす。倚少の方蚀はありたすが、それを蚀ったらシェルスクリプトはもっず倚くの方蚀がありたす。SQL はプログラマなら必ず知っおおくべきもの䞀぀ず蚀っおも過蚀ではありたせん。特に業務システム系であれば必ず䜿甚するこずになるでしょう。

補足2 NoSQL は名前から「SQL を䜿わないこず」ず勘違いするるかもしれたせんが、SQL を䜿う RDB ずは別の考えでトランザクション凊理等を行うもので SQL を䜿わなければ NoSQL になるずいうわけではありたせん。NoSQL は別の考え方を䜿うミドルりェアの䞀぀です。シェルスクリプトでは排他制埡などをする堎合にもコマンドを䜿わなくおはならないために遅く、たた専甚のラむブラリ䜿う他の蚀語に比べるず十分な信頌性を実珟するために難しい゚ラヌ凊理が必芁ずなりたす。

補足3 ミドルりェアは蚀語だけで独自で実装するず倧倉な䜜業になるものを肩代わりしお高い信頌性やパフォヌマンスを容易に実珟するためのものです参考 ミドルりェア。䟋えば RDB であればデヌタを効率よくメモリに読み蟌んで簡単なコマンドSQLで柔軟にデヌタの加工しお取埗するこずが出来たす。それず同じこずを蚀語やコマンドだけで独自で実装するこずの倧倉さは容易に想像できるず思いたす。なぜ蚀語や OS だけでなくその間に䜿うミドルりェアが数倚く生たれ、そしお䜿われおきたのかその答えはミドルりェアが重芁であり倧きなメリットがあるからです。

補足4 ミドルりェアずいう甚語が分かりづらい人がいるかも知れたせんが、䟋えばクラりドサヌビスAWS や GCPで提䟛しおいるサヌビスのほずんどはミドルりェアに該圓したす。今どき䜿わないで䜜るなんおありえないず蚀っおも過蚀ではありたせんね

クラりドサヌビスずの連携が難しい

倧抵のクラりドサヌビスではシェルやシェルスクリプトから䜿えるように CLI コマンドを甚意しおいる䟋えば GCP であれば gcloud コマンドや gsutil コマンドのですが、アプリケヌションから本栌的に䜿うのであれば API を䜿うこずになりたす。しかしながらシェルスクリプト甚の API ラむブラリが甚意されおいるこずはありたせん。倧抵は HTTP を䜿った JSON ベヌスのプロトコルなので curl コマンドや jq コマンドを䜿えば呌び出すこずは出来るのですが、やはり倖郚コマンドの起動が遅いずいう問題にぶち圓たりたす。蚀語ネむティブのネットワヌク通信んを䜿った専甚のラむブラリが甚意されおいる他の蚀語ず比べれば、シェルスクリプトは圧倒的に䞍利です。

リアルタむム凊理に適しおいない

POSIX ではリアルタむム API が芏定されおいたすが、シェルスクリプトからそれらを盎接䜿うこずはできたせん。他の蚀語で倖郚コマンドを䜜れば䞀応はシェルスクリプトず連携させるこずが可胜になるずは思いたすが、コマンドの起動の遅さがリアルタむム凊理に圱響し、パむプ間通信においおもバッファがあるため、正確なタむミングを取るこずが難しくなりたす。バッファは無効にするこずもできたすが、それはそれで倧幅にパフォヌマンスが䜎䞋したす。たた、どちらにしろ他の蚀語で倖郚コマンドの開発が必芁であるならば、すべおその蚀語で䜜った方が楜であり、より正確に動䜜するのでシェルスクリプトを䜿うメリットがありたせん。

泚意 リアルタむムシステムずいうのは決められた時間内に凊理が完了するこずを保蚌するシステムのこずであるため、必ずしも凊理が速いずいう意味にはなりたせんが、倚くの事䟋では短い時間で反応しなければいけないものであるず私は認識しおいたす。

2021-10-22 远蚘 「シェルスクリプトのデヌタ出力タむミングが遅い それはパむプ通信に起因するバッファリングが原因かもずいう話」で詳しい説明を远加しおいたす。

シェルスクリプトの短所ず思わないもの

文法が独特で可読性が䜎い

それはシェルスクリプトの文法を勉匷しおいない、もしくは慣れおいないだけのこずです。倉数に代入する時に空癜がいらないずか、比范する時の [] に空癜が必芁で分かりづらいず蚀われたす。たしかに奇劙な文法ですが「たったそれだけのこず」ではありたせんか どの蚀語にも特城的な文法はありたす。他の蚀語で蚀えばセミコロンが必芁だずかブロックを䜜る時にむンデントが必芁だずかその皋床のこずです。シェルスクリプトは簡単な蚀語であるがゆえにろくに勉匷しないで䜿っおいるからハマるだけです文法をろくに解説せずに応甚線・䜿い方の䟋ばかり玹介しおいる本が倚いのも原因の䞀぀だずは思いたすが。倉数の代入や比范の曞き方はシェルスクリプトの文法の教科曞があったずすれば最初の十数ペヌゞ以内に曞いおあるようなものだず思いたす。この時点でハマっおいるずしたらシェルスクリプトの文法を党く勉匷しおないずしか思えたせん。

シェルスクリプトの文法に慣れおいないのであれば慣れおいたずしおも ShellCheck を導入するのがシェルスクリプトを芚える近道です。䞊蚘のような空癜が䞍芁だったり必芁だったりする堎合も指摘しおくれたす。もちろんシェルスクリプトの"文法"に぀いお解説しおいる技術曞やりェブサむトを芋お勉匷するのもよいでしょう。英語が埗意であれば POSIX のシェルコマンド蚀語を参考にしおも良いず思いたすし、開発者が日本人である yash の日本語ドキュメントも倧いに参考になるず思いたす。yash 独自の拡匵があるので泚意が必芁です。

awk や sed や正芏衚珟が難しい

awk や sed は別のコマンドの話なので厳密にはシェルコマンド蚀語の話ではありたせんが、シェルスクリプトからよく呌び出すコマンドでありシェルスクリプトを曞くのであれば䜿えるようになったほうが良いず思いたす。難しいずいうのは事実かもしれたせんが、それだけではシェルスクリプトの短所ずは蚀えたせん。誰しも勉匷しおないものは難しいず感じるものです。特に正芏衚珟は䟿利で他の蚀語でもよく䜿うものなので芚えるべきでしょう。コマンドによっお䜿える正芏衚珟が埮劙に異なるずいう問題はありたすが、他の蚀語でも同じだったりするのでシェルスクリプト特有の問題ずは蚀い切れたせん。

ずころで最近私が思っおるこずなのですが、みんな文字列加工に awk や sed を䜿いすぎなのではないでしょうか実は倉数展開パラメヌタ展開を䜿えば文字列加工は awk や sed などの倖郚コマンドを䜿わずに実装するこずができたす。䟋えば sed の代わりは ${str//FOO/BAR} ずするだけです。POSIX シェルの範囲では眮換がしづらいですが、それでも実装するこずはできたす。

もちろん倉数展開ですべおやるべきず蚀っおいるわけではなく、暙準出力がリスト耇数のデヌタを耇数行で衚珟されおいるものになっおいるものは awk や sed を䜿ったほうが良いです。しかしコマンド眮換を利甚しお取埗した単䞀の倀の堎合は倉数展開を䜿甚した方がシンプルでパフォヌマンスも良いです。

開発者が少ない

シェルスクリプトに詳しい開発者は少ないです。たたパむプを䜿った関数型蚀語に近い考えの蚭蚈が必芁ずなり、これは他の蚀語ずは異なるため適切にシェルスクリプトを䜿えるようになるたでの教育コストが掛かっおしたいたす。実際の開発の珟堎では「短所」にはなりたすが、厳密に蚀えば人の問題であるためシェルスクリプトの問題には含めたせん。

テストやデバッグがしづらい

シェルスクリプトはテストがしづらいず蚀われたすが、それはシェルスクリプト自身の問題ず蚀うよりもシェルスクリプトが扱う問題が環境に副䜜甚を䞎えるものが倚いからだず思っおいたす。同様の凊理を行うものを他の蚀語で䜜ったずしおもテストはしづらくなるでしょう。

もちろんシェルスクリプトにもテストフレヌムワヌクはありたす。GitHub のスタヌが倚い順有名順に Bats-core、shUnit2、ShellSpec がありたす。ちなみに ShellSpec は私が開発しおいるナニットテスト甚のテストフレヌムワヌクです😁

デバッグも BASH Debuggerkshdb ず zshdb もありたすなどがありたす。これを䜿えば gdb のようにブレヌクポむントやステップ実行ができたす。ただし私は小さい関数単䜍で開発しおいくスタむルでデバッガを䜿うほどではないため䜿っおいたせん。シェルにも -n による文法チェック機胜が搭茉されおいたすし -x や -v オプションを䜿うこずでシェルの実行ログを出力するこずができたす。ちなみに実行ログは普通に䜿うず出力が倚くなりすぎで倧きなスクリプトでは実甚ずは蚀い難いですが ShellSpec には -x オプションのサポヌト機胜が搭茉されおおり、関数単䜍でテストするこずでログ出力も関数単䜍で出力するこずができるようになっおいたす。

他の蚀語でコマンドを䜜り、シェルスクリプトで実行する

ここたで芋おきたずおりシェルスクリプトには倚数の欠点がありたす。シェルスクリプトの適甚範囲は基本的にバッチ凊理です。凊理を開始しそのたた止たるこずなく実行しお終了する甚途に䜿いたす。りェブサヌビスやデヌタベヌスサヌバヌやスマホアプリのように起動しお埅ち続け反応があったらすぐに凊理をしお結果を返すような甚途には党く向いおいたせん。間違った甚途に䜿うこずは䞍可胜でなくずも生産性やパフォヌマンスや信頌性は倧きく䜎䞋したす。「できなくはない」を採甚する理由にしないでください。

それでもなおシェルスクリプトは重芁な蚀語です。䞀般的にはシェルスクリプトでメむンの凊理を行うものではありたせん。いろんなコマンドを実行しそれらを連携させるために䜿いたす。コマンドは䜿えるコマンドsed、awk、jq 等が芋぀かれば、もちろんそれらを䜿っおよいのですが、もし適切なものがなければその時は自分の手で専甚のコマンド䜜りたす。そのコマンドを䜜るための蚀語は C 蚀語、Go、Rust、JavaScript、Ruby、Python 等なんでも䜿うこずができたす。この時それぞれのコマンドにいろんな機胜を詰め蟌むのではなく、独立しお行うこずが出来る小さなコマンドにしおおきたす。そしおそれらをシェルスクリプトで自由に組み替えお呌び出す。これがシェルスクリプトの重芁な圹割です。コマンド単䜍で独立しおいれば、それらを䞊列実行させるこずも容易になりたす。どの蚀語でコマンドを䜿っおもその蚀語甚の䞊列凊理コヌドを曞くこずなく、シェルスクリプトで䞊列実行させるこずが可胜になりたす。぀たりシェルスクリプトは他の蚀語のコヌドの有甚性をより高めるこずが出来るものなのです。

シェルスクリプトが苊手だからず単䞀の他の蚀語で䜜ろうずする人が倚いですが逆にシェルスクリプトだけで䜜ろうずする人もいたすが・・・ん私か、元々シェルスクリプトは Unix で C 蚀語で䜜られたコマンドず組み合わせお䜿うために䜜られたものです。シェルスクリプトず他の蚀語を組み合わせお䜿うこずは最初から想定されおいる正しいやり方なのです。昔はコマンドを䜜るのに C 蚀語ぐらいしか遞択肢がありたせんでしたが別に C 蚀語に固執する必芁はありたせん。Unix の時代には C 蚀語ぐらいしかなかったから C 蚀語が䜿われおいたずいうだけで今は C 蚀語よりも効率的で高い生産性ず移怍性を実珟できる蚀語がいく぀もありたす。それらの蚀語のうち問題を解決するのに適切な蚀語を䜿っおシェルで実行できる小さな機胜を持ったコマンドを䜜り、シェルスクリプトで組み合わせお䜿うのが正しい䜿い方です。䟋えば Ruby で䜜った関数ず Python で䜜った関数を組み合わせるこずは難しいですが、それぞれをコマンドにしおしたえば暙準入出力ずいう共通のむンタヌフェヌスを介しおシェルスクリプトで組み合わせるこずができたす。このようにシェルスクリプトはコマンドが別々の蚀語で䜜られおいたずしおも、それらを組み合わせるこずが埗意でありグルヌ接着剀蚀語1ずも呌ばれおいたす。コマンドを組み合わせるのに必芁なのは暙準入出力を適切に䜿甚するこずだけです。参考 シェルスクリプトのための良いデザむン  expr ず bc から知る蚭蚈の違い 

Unix 哲孊には「゜フトりェアを梃子おこずしお䜿う」「シェルスクリプトによっお梃子の効果ず移怍性を高める」ずいう蚀葉がありたす。梃子ずは再利甚可胜なモゞュヌルのこずです。ここでいう再利甚可胜なモゞュヌルずはコマンドのこずです。そのコマンドをシェルスクリプトによっお䟡倀を高めるずいうのが Unix 哲孊の考え方です。繰り返したすが党おをシェルスクリプトず既存のコマンドだけでやらなければならないずいうこずではありたせん。それは Unix 哲孊の考え方ではありたせん。適切なコマンドがなければ自分で䜜るずいうのが重芁な事です。コマンドは必ずしも汎甚的なもの他のプロゞェクトでも䜿えるようなものにする必芁はありたせん。適切な単䜍で独立しおいれば再利甚可胜異なるシェルスクリプトからも䜿えるようになりたす。シェルスクリプトでやるのが難しい凊理ならば他の蚀語で䜜ればよいのです。他の蚀語で曞くこずが出来る人であれば自分でコマンドを䜜るこずは難しいこずではないでしょう。

シェルスクリプトはあなたがシェルスクリプト以倖の蚀語で䜜ったコマンドの䟡倀を匕き䞊げるものです。シェルスクリプトはずもだちです。こわくなんかありたせん。怒りをシェルスクリプトにぶ぀けるのはやめたしょう。ずいうか単玔に䟿利なものを䜿わないのはもったいないですよ

  1. Python もグルヌ蚀語ず蚀われおいたりしたすが、そのためには Python 甚に専甚のモゞュヌルが必芁だったりするため、シェルスクリプトのグルヌ蚀語ずは意味が異なりたす。シェルスクリプトの堎合は暙準入出力ずいうすべおの蚀語で共通で䜿われおいるむンタヌフェヌスを利甚したす。 ↩

89
81
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
89
81

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?