# TLCL 輪読会 ## 32 - Positional Parameters 2023/10/03 [@kdnakt](https://twitter.com/kdnakt) --- #### これまでに書いたシェルスクリプト - コマンドラインのオプションや引数なし - それでいいの? --- ## 今日の範囲 ### 32 - Positional Parameters - Accessing the Command Line - Handling Positional Parameters en Masse - A More Complete Application --- ### Accessing the Command Line - 位置パラメータ - $0:実行されるプログラムのパス名 - $1〜$9以降:渡された引数 - `${10}`以降:`${10}`, `${55}`, `${211}`... ---- - 位置パラメータの使い方 ```shell! #!/bin/bash # posit-param: コマンドラインパラメータを表示する echo " \$0 = $0 \$1 = $1 \$2 = $2 \$3 = $3 \$4 = $4 \$5 = $5 \$6 = $6 \$7 = $7 \$8 = $8 \$9 = $9 " ``` ---- - 実行結果 ```shell! ~$ posit-param a b c d $0 = /home/me/bin/posit-param $1 = a $2 = b $3 = c $4 = d $5 = $6 = $7 = $8 = $9 = ``` ---- #### Determining the Number of Arguments - `$#`:引数の数にアクセスできる ```shell! #!/bin/bash echo " Number of arguments: $# \$0 = $0 \$1 = $1 \$2 = $2 " ``` ```shell! ~$ posit-param a b Number of arguments: 2 $0 = /home/me/bin/posit-param $1 = a $2 = b ``` ---- #### shift - Getting Access to Many Arguments - 引数が多いときにどう処理するか? - `shift`コマンドでずらす - `$2`が`$1`に、`$3`が`$2`に移動する - `$0`は変化しない ---- - shiftの使い方 ```shell! #!/bin/bash # posit-param2: 全パラメータを表示するスクリプト count=1 while [[ $# -gt 0 ]]; do     echo "Argument $count = $1"     count=$((count + 1))     shift done ``` ``` $ ./posit-param2 a b c d Argument 1 = a Argument 2 = b Argument 3 = c Argument 4 = d ``` ---- #### Simple Applications - shiftなしのシンプルな実装 - basenameコマンド - パスからファイル名のみ抽出 ```shell! #!/bin/bash # file-info: シンプルなファイル情報表示 PROGNAME="$(basename "$0")" if [[ -e "$1" ]]; then     echo -e "\nFile Type:"     file "$1"     echo -e "\nFile Status:"     stat "$1" else     echo "$PROGNAME: usage: $PROGNAME file" >&2     exit 1 fi ``` ---- #### Using Positional Parameters with Shell Functions - 位置パラメータはシェル関数でも利用可能 - `.bashrc`などで活躍 - `$FUNCNAME`:自動的更新される変数 ```shell! file_info () {     # file_info: ファイル情報を表示する関数     if [[ -e "$1" ]]; then         echo -e "\nFile Type:"         file "$1"         echo -e "\nFile Status:"         stat "$1"     else         echo "$FUNCNAME: usage: $FUNCNAME file" >&2         return 1     fi } ``` --- ### Handling Positional Parameters en Masse - 位置パラメータをまとめて扱う - 別のプログラムのラッパーなど - 2つの特別なパラメータ:`$*`と`$@` - どちらも位置パラメータのリストに展開 - ダブルクオートありの動作が異なる - `"$*"`:1つの文字列になる - `"$@"`:個別の引数になる ---- - posit-params3: `"$*"`と`"$@"`の比較 ```shell! #!/bin/bash print_params () {     echo "\$1 = $1"     echo "\$2 = $2"     echo "\$3 = $3"     echo "\$4 = $4" } pass_params () {     echo -e "\n" '$* :'; print_params $*     echo -e "\n" '"$*" :'; print_params "$*"     echo -e "\n" '$@ :'; print_params $@     echo -e "\n" '"$@" :'; print_params "$@" } pass_params "word" "words with spaces" ``` ---- - 実行結果 ```shell! ~$ posit-param3 $* : $1 = word $2 = words $3 = with $4 = spaces "$*" : $1 = word words with spaces $2 = $3 = $4 = ``` ```shell! $@ : $1 = word $2 = words $3 = with $4 = spaces "$@" : $1 = word $2 = words with spaces $3 = $4 = ``` ---- - 引数が"word"と"words with spaces"の場合 - `"$*"`= `"word words with spaces"` - `"$@"`= `"word" "words with spaces"` - 元の引数が維持される`"$@"`の方が便利 --- ### A More Complete Application - 25章,27章の`sys_info_page`への機能追加 - ヘルプ - インタラクティブモード - ファイル出力機能 ---- - ヘルプの実装と引数処理 ```shell! # ヘルプのシェル関数 usage () {     echo "$PROGNAME: usage: $PROGNAME [-f file | -i]"     return } ``` ```shell! # コマンドラインオプションを処理 interactive= filename= while [[ -n "$1" ]]; do     case "$1" in         -f | --file) shift                                  filename="$1"                                  ;;         -i | --interactive) interactive=1   ;; -h | --help) usage           exit           ;; *)                     usage >&2           exit 1           ;;     esac     shift done ``` ---- - インタラクティブモードの実装 ```shell! if [[ -n "$interactive" ]]; then     while true; do         read -p "Enter name of output file: " filename         if [[ -e "$filename" ]]; then             read -p "'$filename' exists. Overwrite? [y/n/q] > "             case "$REPLY" in                 Y|y) break   ;; Q|q) echo "Program terminated."   exit   ;; *)     continue   ;;     esac ``` ```shell! elif [[ -z "$filename" ]]; then     continue else     break fi     done fi ``` ---- - ファイル出力の実装(1) ```shell! write_html_page () { cat <<- _EOF_ <html><head><title>$TITLE</title></head> <body> <h1>$TITLE</h1> <p>$TIMESTAMP</p> $(report_uptime) $(report_disk_space) $(report_home_space) </body> </html> _EOF_ return } ``` ---- - ファイル出力の実装(2) ```shell! # HTMLを出力 if [[ -n "$filename" ]]; then if touch "$filename" && [[ -f "$filename" ]]; then write_html_page > "$filename" else echo "$PROGNAME: Cannot write file '$filename'" >&2 exit 1 fi else write_html_page fi ``` --- ### Summing Up - これで終わりじゃないよ! - 次回、for文でさらに改善しよう
{"title":"TLCL輪読会32章","slideOptions":"{\"transition\":\"slide\"}","description":"2023/10/03 kdnakt","contributors":"[{\"id\":\"df36d0f0-b67e-41ac-96b3-f3988326d230\",\"add\":6370,\"del\":1190}]"}
    357 views