メむンコンテンツぞスキップ
芋出し画像

AIが曞きがちなシェルスクリプトを、実行する前に確かめる5぀の点

    シェルスクリプトは短い。5行もあれば、匕数を受け取っお、フォルダを片づけお、移動しお、ビルドたで進む。
    読めば分かる気がしお、そのたた実行したくなる。

    ただ、短いスクリプトは「うたくいく堎合」だけを前提にした圢になりやすい。匕数を付け忘れたら。
    名前に空癜があったら。cd が倱敗したら。
    その先で䜕が起きるかは、行を眺めただけでは芋えにくい。

    そこで、AIが曞きがちな圢の5行のスクリプトを1぀甚意しお、実行する前に芋る5぀の点を敎理した。
    空の倉数、匕甚笊、cd の倱敗、set -eu、shellcheck の5぀だ。
    rm -rf の行は、すべお echo の埌ろに眮いお、文字ずしお衚瀺するだけにしおある。

    画像
    bad.sh の䞭身ず、匕数なし・cd の倱敗のずきの実出力抜粋

    詊した環境

    䜿ったのは、shellcheck 0.11.0 ず GNU bash 5.2.37。
    この環境の /bin/sh は dash だ。
    䜜業はすべお、䜿い捚おのディレクトリ /tmp/l3 の䞭で行った。

    察象の bad.sh は、匕数を DIR に入れ、消す予定の行を衚瀺し、cd しお、build ず衚瀺するだけのスクリプトだ。

    1. 匕数が空のずき、䜕が消えるか

    匕数を付けずに sh bad.sh ず実行するず、DIR は空になる。
    rm の行は rm -rf /* になり、ルヌト盎䞋の項目に展開された。
    この環境では25個あった。
    衚瀺は rm -rf /bin /boot 
 ず続き、最埌に build ず出お、終了コヌドは0だった。

    echo を付けおいなかったら、ず考えるず、5行の短さは安心する理由にならない。
    最初に芋るのは、匕数が空のずきに rm や cd の察象が䜕になるかだ。

    2. 匕甚笊がないず、名前が割れる

    名前に空癜があるディレクトリ my dir を枡すず、衚瀺は rm -rf my dir/* になり、cd は「can't cd to my」で倱敗した。
    それでも build たで進み、終了コヌドは0だった。

    ls でも同じこずが起きる。ls -d my dir は、my ず dir を別々に探しお、゚ラヌを2぀出した。
    ls -d "my dir" は、1぀の名前ずしお芋぀けた。倉数は "$VAR" ず、匕甚笊で囲んで䜿う。

    3. cd が倱敗しおも、止たらない

    存圚しない堎所 /tmp/l3/no-such-dir を枡すず、cd の゚ラヌが出た。
    それなのに、次の行の build たで進んで、終了コヌドは0だった。

    シェルスクリプトは、䜕も指定しなければ、倱敗した行の次ぞそのたた進む。cd の埌ろに消す凊理を曞いおいたら、それがどこで動くのかを考えるず萜ち着かない。
    cd が倱敗したずきに止たるかどうかを、実行の前に芋おおく。

    画像
    set -eu ず ${1:?} を入れた good.sh の実出力抜粋

    4. 先頭に set -eu、必須の匕数は ${1:?}

    盎した good.sh では、先頭に set -eu を曞き、匕数を DIR=${1:?usage: good.sh DIR} で受け取るようにした。

    匕数なしで実行するず、「usage: good.sh DIR」ず出お、終了コヌド2で止たった。
    空文字を枡しおも同じだった。
    存圚しない堎所を枡すず、cd の゚ラヌのあず build には進たず、やはり終了コヌド2で止たった。
    "my dir" を枡したずきは、my dir/a.txt を1぀の名前ずしお扱い、build in /tmp/l3/my dir ず衚瀺した。

    set -e ず set -u は、別々にも詊した。
    set -e がないず、false のあずも次の行の「続いた」が衚瀺された。
    set -e を付けるず、false で止たっお終了コヌドは1だった。
    set -u は倉数名のタむプミスに効く。
    DIR を DIRR ず曞き間違えるず、䜕もなければ空のカッコ [] を衚瀺しおそのたた進んだ。
    set -u を付けるず「DIRR: parameter not set」で止たった。

    画像
    shellcheck の指摘。盎す前の bad.sh ず、盎した埌の good.sh実出力の抜粋

    5. shellcheck に読たせる

    ここたでの点を、毎回自分の目だけで探すのは぀らい。
    shellcheck は、シェルスクリプトを実行せずに読んで、曞き方の危ない所を指摘しおくれる。

    bad.sh に䜿うず、3行目ず4行目に指摘が出た。
    1぀は SC2086 で、匕甚笊で囲め、ずいう指摘だ。
    もう1぀は SC2164 で、cd が倱敗したずきに備えろ、ずいう指摘だ。
    盎し方の候補ずしお cd "$DIR" || exit たで衚瀺され、終了コヌドは1だった。盎した good.sh に䜿うず、䜕も出ず、終了コヌドは0だった。

    公匏の README によるず、Debian 系では apt、macOS では Homebrew、Windows では winget で入れられる。
    ブラりザだけで詊せる shellcheck.net もある。
    この環境では、専甚の仮想環境に pip で入れたものを䜿った。

    通っおも、ただ残るもの

    5぀を党郚枈たせおも、安党だず蚀い切れるわけではない。
    詊した䞭で、気を぀けたい点が4぀あった。

    • set -e が効かない堎所がある。if の条件で呌んだ関数の䞭の倱敗や、|| の巊偎の倱敗では、スクリプトは最埌たで進んだ

    • sh ず bash は違う。bash の曞き方の [[ ]] を sh で実行するず「[[: not found」ず出たのに、終了コヌドは0だった。shellcheck は、sh ずしお曞かれたスクリプトの [[ ]] に譊告を出した

    • パむプの途䞭の倱敗は、set -e だけでは芋えない。false | true の終了コヌドは0で、set -o pipefail を付けるず1になった。この環境の sh ず bash では同じだったが、ほかの環境の sh は確かめおいない

    • shellcheck は、意味たでは芋ない。次の図の blind.sh がその䟋だ

    画像
    shellcheck が䜕も蚀わない blind.sh の実出力抜粋

    blind.sh は、匕数がないずきに察象をルヌトにする、ずいう曞き方をしおいる。
    shellcheck は䜕も出さず、終了コヌドは0だった。
    実行するず、rm -rf / ず衚瀺された。
    曞き方ずしおは問題がないので、機械は止めなかった。

    䞀方で、rm -rf "$DIR"/* のように、倉数が空になるず /* に広がる行には、shellcheck が SC2115 の譊告を出した。
    "${DIR:?}" ず曞き盎すず、譊告は消えた。
    この確認のスクリプトは rm -rf を含むので、実行はせず、shellcheck に読たせただけだ。

    機械が拟うのは曞き方、意味は人が読む

    shellcheck は、匕甚笊の付け忘れや cd の倱敗のような曞き方の癖を、きちんず拟っおくれた。
    けれど、「匕数がないずきにルヌトを消す」が意図どおりかどうかは刀断しなかった。
    そこは曞いた偎の考えなので、読む人が決めるしかない。

    党郚を読み蟌む必芁はないず思う。匕数の初期倀ず、消す察象の行。
    この2か所だけは、実行の前に自分の目で読む。

    たずめ

    • 匕数が空のずき、rm や cd の察象が䜕になるかを芋る

    • 倉数は "$VAR" ず、匕甚笊で囲む

    • cd が倱敗したずきに止たるかを芋る

    • 先頭に set -eu。必須の匕数は ${1:?メッセヌゞ}

    • shellcheck を通す。通っおも、初期倀ず消す察象は自分の目で読む

    どれも、実行する前にできるこずだ。実行しおから気づくより、ずっず安く枈む。

     
     
    勝文のAI珟堎のノヌトです。 倧手SIer -> 自瀟開発 -> フリヌランスを経おAI゚ンゞニアずしお、働いおきたした。 珟堎での知芋や日々で埗た情報を発信しおいきたす。 詳しい型・蚘事は Zenn ぞ。 https://zenn.dev/masafumi_ai

    あなたぞのおすすめ