# TLCL 輪読会 ### 27 – Flow Control: Branching with if 2023/08/15 [@kdnakt](https://twitter.com/kdnakt) --- ## 今日の範囲 ### 27 – Flow Control: Branching with if - if - Exit Status - test - A More Modern Version of test - (( )) - Designed for integers - Combining Expressions - Control operators: Another Way to Branch --- ### if - シンプルな例 ```bash x=5 if [ "$x" -eq 5 ]; then echo "x equals 5." else echo "x does not equal 5." fi ``` ---- - 複雑な例 ```bash if commands; then commands [elif commands; then commands ...] [else commands] fi ``` --- ### Exit Status - コマンドが返す値 (スクリプトやシェル関数を含む) - 0〜255 - 0が成功、それ以外は失敗 - 詳細はman pageに ```bash! $ ls -d /usr/bin /usr/bin $ echo $? 0 $ ls -d /bin/usr ls: cannot access /bin/usr: No such file or directory $ echo $? 2 ``` ---- - ビルトインコマンド - `true`:常に終了ステータス0 - `false`:常に終了ステータス1 ```bash $ if true; then echo "It's true."; fi It's true. # 複数コマンドの場合は最後のコマンドの結果で分岐 $ if true; false; then echo "It's true."; fi $ ``` --- ### test - ifで最頻出のコマンド:test - 以下2つは同じ意味 - test *expression* - [ *expression* ] - bashでは`[`はビルトインコマンド ---- #### File Expressions - `f1 -ef f2`:f1とf2が同一ファイル - `f1 -nt f2`:f1が新しい - `f1 -ot f2`:f1が古い - `-b file`:存在するブロックデバイス - `-c file`:存在するキャラクタデバイス - `-d file`:存在するディレクトリ - `-e file`:存在する - `-f file`:存在するファイル ---- - `-g file`:存在し、setgidアクセス権あり - `-G file`:存在し、実効グループID所有 - `-k file`:存在し、スティッキービットあり - `-L file`:存在するシンボリックリンク - `-O file`:存在し、実効ユーザーID所有 - `-p file`:存在する名前付きパイプ - `-r file`:存在し読み込み可能 - `-s file`:存在し長さ1以上 - `-S file`:存在するネットワークソケット ---- - `-t fd`:端末でオープンされているfd - `-u file`:存在し、setuidアクセス権あり - `-w file`:存在し書き込み可能 - `-x file`:存在し実行可能 ---- ```bash! FILE=~/.bashrc if [ -e "$FILE" ]; then if [ -f "$FILE" ]; then echo "$FILE is a regular file." fi # 省略 else # 省略 fi ``` ---- #### String Expressions - `str`:strがnullでない - `-n str`:strの長さが1以上 - `-z str`:strの長さが0 - `str1 = str2`:等しい。POSIX標準。 - `str1 == str2`:等しい。bash版。 - `str1 != str2`:等しくない - `str1 > str2`:str1のソート順が後 - `str1 < str2`:str1のソート順が先 ---- - 実例 ```bash! ANSWER=maybe if [ -z "$ANSWER" ]; then echo "There is no answer." >&2 exit 1 fi if [ "$ANSWER" = "yes" ]; then echo "The answer is yes." elif [ "$ANSWER" = "no" ]; then # 省略 fi ``` - `<`や`>`はリダイレクト演算子 - ""で囲むかエスケープ必要 ---- #### Integer Expressions - `int1 -eq int2`:等しい - `int1 -ne int2`:等しくない - `int1 -le int2`:以下 - `int1 -lt int2`:未満 - `int1 -ge int2`:以上 - `int1 -gt int2`:より大きい ---- - 実例: ```bash #!/bin/bash INT=-5 if [ -z "$INT" ]; then echo "INT is empty." >&2 exit 1 fi if [ "$INT" -eq 0 ]; then echo "INT is zero" else # 次ページへ fi ``` ---- - 正負、偶数奇数判定 ```bash! if [ "$INT" -lt 0]; then echo "INT is negative." else echo "INT is positive." fi if [ $((INT % 2)) -eq 0]; then echo "INT is even." else echo "INT is odd." fi ``` --- ### A More Modern Version of test - [[ *expression* ]] - 新しいbashでtestの代わり - testコマンドの式を全てサポート - `string1 =~ regex`を実装 - `==`演算子でパターンマッチング可能 ``` $ if [[ $FILE == foo.* ]]; then > echo "$FILE は 'foo.*' パターンにマッチ" > fi $FILE は 'foo.*' パターンにマッチ ``` ---- - 先ほどの例をリライト ```bash INT=-5 # 拡張正規表現をサポート if [[ "$INT" =~ ^-?[0-9]+$ ]]; then if [ "$INT" -eq 0 ]; then echo "INT is zero." else # 省略 fi fi ``` --- ### (( )) - Designed for integers - bashの整数演算用コマンド - 詳細はChapter 34 - `((1))`はtrue - `((0))`はfalse ---- - 先ほどの例をリライト ```bash! INT=-5 # $による変数展開不要 if ((INT == 0)); then echo "INT is zero" else if ((INT < 0)); then echo "INT is negative" else echo "INT is positive" fi # 省略 fi ``` --- ### Combining Expressions - 論理演算子の違い |演算子 |test | [[ ]]/(( )) | |----|-----|--------| |AND |-a | && | |OR |-o | \|\| | |NOT |! | ! | ---- - ANDの例 ```bash! MIN=1 MAX=100 INT=50 if [[ "$INT" -ge "$MIN" && "$INT" -le "$MAX" ]]; then echo "$INT is within $MIN to $MAX." else echo "$INT is out of range." fi ``` ---- - NOTの例 ```bash! MIN=1 MAX=100 INT=50 if [[ !("$INT" -ge "$MIN" && "$INT" -le "$MAX") ]]; then echo "$INT is outside $MIN to $MAX." else echo "$INT is in range." fi ``` ---- #### testか`[[ ]]`か - testコマンド:伝統的POSIX標準 - 広く利用されている - 可搬性があるが進歩がない - `[[ ]]`:bashなどモダンシェルで利用可 - 使いやすくコーディングしやすい - bashインストール必要 --- ### Control operators: Another Way to Branch - bashの制御演算子 - `c1 && c2`:c2はc1がtrue時のみ実行 - `c1 || c2`:c2はc1がfalse時のみ実行 - 実例 - `mkdir temp && cd temp` - `[[ -d temp ]] || mkdir temp` - `[[ -d temp ]] || exit 1` --- ### Summing Up - 問:sys_info_pageスクリプトでパーミッションをチェックするには? - 答:report_home_space関数を修正 ```bash report_home_space () { if [[ "$(id -u)" -eq 0]]; then cat << _EOF_ <h2>Home Space Utilization (All Users)</h2> <pre>$(du -sh /home/*)</pre> _EOF_ else cat << _EOF_ <h2>Home Space utilization ($USER)</h2> <pre>$(du -sh $HOME)</pre> _EOF_ fi return } ```
{"slideOptions":"{\"transition\":\"slide\"}","title":"TLCL 輪読会 27章","description":"2023/08/15 @kdnakt","contributors":"[{\"id\":\"df36d0f0-b67e-41ac-96b3-f3988326d230\",\"add\":5067,\"del\":133}]"}
    266 views