&tag(Bash); *目次 [#k301f9e1] #contents *参考情報 [#v39c8200] -[[OKLab - Bourneシェルスクリプト入門(+bash):http://www.oklab.org/program/sh.html]] -[[bash 入門:http://www.hpc.cs.ehime-u.ac.jp/~aman/linux/bash/]] *規約に関して [#ldaba577] -[[シェルスクリプト Tips - UNIX & Linux コマンド・シェルスクリプト リファレンス:http://shellscript.sunone.me/tips.html]]。ファイル名の命名方法とか参考になる。 -[[シェルスクリプトのコーディングスタイル・コーディング規約について考えてみる - 双六工場日誌:http://sechiro.hatenablog.com/entry/2013/05/12/%E3%82%B7%E3%82%A7%E3%83%AB%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%81%AE%E3%82%B3%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%83%BB%E3%82%B3%E3%83%BC]] -[[ShellScript - シェルスクリプトを書くときに気をつける9箇条 - Qiita:http://qiita.com/b4b4r07/items/9ea50f9ff94973c99ebe]] **変数名の規約 [#rb2c3908] -ローカル変数: 小文字、グローバル変数: 大文字、エクスポートする変数: 大文字。 -インデントはスペース4個。 -readonlyはできれば使う。exportと併用する場合、readonlyで定義してそのあとexportすれば良い。 -ファイル名の名前だけFOO_FILENAME、フルパスFOO_FILE。ディレクトリ名の名前だけFOO_DIRNAME、フルパスFOO_DIR **デフォルトオプション [#o0d24102] -かならずset -euする。set -eでエラーで止まる。set -uで未定義変数でエラー。[[Bash - シェルスクリプトを書くときはset -euしておく - Qiita:http://qiita.com/youcune/items/fcfb4ad3d7c1edf9dc96]] -set -uするとコマンドライン引数が指定されなかったときに、$1がエラーになる。これを防ぐためにはデフォルト値を使う。 TASKNAME=${1:-default unknown_task} *パラメータ [#y79b6f9d] ,$0,コマンド名 ,$1,1つ目の引数 ,$2,2つ目の引数 ,$*,残りの引数全部 ,$# ,引数の個数 *変数 [#id0375d1] **参考 [#oe39a741] -[[bash シェルスクリプト -PG's PocketArms:http://himana.natsu.gs/bash-001.html]] **基本 [#u13bee70] -小文字でも大文字でも良い。 -宣言時は$を頭につけない。両端にスペースをいれない。 -参照時は$を頭につける。厳密に使いたい時は変数名を{}で囲う必要もある。 #pre{{ a="XYZ" echo "$a" echo "${a}" }} -空白がはいった変数のことを考えると、変数使用時常にダブルクォートで囲ったほうが安全かも。if文でエラーにならないように。 **環境変数とシェル変数 [#x1ba97f5] -[[シェル変数と環境変数の違い - 燈明日記:http://d.hatena.ne.jp/chaichanPaPa/20090517/1242542427]]によると、ざっくり言ってローカル変数=シェル変数、グローバル変数=環境変数と考えて良い。 -別に大文字=環境変数というわけではない ***環境変数 [#ic5e748e] -export FOOのようにexportされた変数が環境変数と呼ばれる。 -printenv FOOで確認できる。 -親シェルでexportされた変数は小シェルに引き継がれる。子で引き継がれた変数を変更しても親には影響しない。 -export済み変数を設定する場合再度exportする必要はない。例えばexport済みのLANGを変更する場合以下でOK。 LANG="hoge" ***シェル変数 [#t55788e4] -そのスクリプトか、または現プロンプト上でしかアクセスが有効でない。 -シェルスクリプトでローカル変数として使えるほか、bashのPS1のような変数にも使われている。 -set PS1のように確認できる。 - set で全部表示できる。 **デフォルト値 [#nf01d82c] -${var:-デフォルト値}で設定できる。 #pre{{ var="a b c" str=${var:-"d e f"} echo $str str=${var2:-"d e f"} echo $str }} -以下が出力される #pre{{ a b c d e f }} -コマンド引数 -以下のシェルスクリプト default.sh を考える。 #pre{{ arg1=${1:-"xxx"} echo $arg1 }} -そのまま実行すると、xxxが出力される。「./default.sh yyy」と実行するとyyyが出力される。 *制御構造 [#k5839b22] **if then else [#h8d19587] -[[test と [ と [[ コマンドの違い - 拡張 POSIX シェルスクリプト Advent Calendar 2013 - ダメ出し Blog:http://fumiyas.github.io/2013/12/15/test.sh-advent-calendar.html]]にあるようにまじめに考えるとかなりめんどくさい。"[["は後から追加されたらしい。 -文字列の比較。"["の両方にスペース。"="の両方にスペースが必要。thenを続ける場合、"]"のあとに";"が必要。 -"-o"は"or" #pre{{ if [ str="a b c d e" if [ "$str" = "a b c" -o "$str" = "a b c d" ]; then echo ok else echo ng fi }} *関数 [#bb3d2895] **パラメータの気温 [#uf134564] -$1,$2のように格納される。そのまま使ってもいいし変数に代入してもよい(厳密にはstrとするとグローバル変数になるのでローカルにしたほうがよい)。 #pre{{ function test() { str=$1 echo "$str" } test a }} **パラメータとして配列を含む引数を渡したい [#a0636306] -ただ単に配列を渡す場合、[[逆引きシェルスクリプト/引数を配列に展開する方法 - Linuxと過ごす:http://linux.just4fun.biz/%E9%80%86%E5%BC%95%E3%81%8D%E3%82%B7%E3%82%A7%E3%83%AB%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88/%E5%BC%95%E6%95%B0%E3%82%92%E9%85%8D%E5%88%97%E3%81%AB%E5%B1%95%E9%96%8B%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95.html]]のように呼び出される側で次のように受ければ良い argv=("$@") -配列のほかにも引数を渡したい場合工夫が必要となる。 ***shift併用型 [#p084954d] -最初の引数とそれ以外の配列引数に分ける。[[Passing arrays as parameters in bash - Stack Overflow:http://stackoverflow.com/questions/1063347/passing-arrays-as-parameters-in-bash]] #pre{{ calling_function() { variable="a" array=( "x", "y", "z" ) called_function "${variable}" "${array[@]}" } called_function() { local_variable="${1}" shift local_array=("${@}") } }} ***動的スコープでそのまま参照 [#q84ee051] -bashの変数は動的スコープなので呼び出し先でそのまま参照できる。local指定しておけばグローバル変数とも区別できる。[[本を読む bashで関数に配列を渡す:http://emasaka.blog65.fc2.com/blog-entry-1223.html]] *コマンド置換 [#d8049cf2] **バッククォート`command`または$(command)を使う [#p874dd44] *Tips [#g322c910] **スクリプトの存在するディレクトリを取得したい [#j053da4c] -スクリプト内から他のスクリプトを呼び出したい場合など、スクリプトが存在するディレクトリが必要になる場合がある。 export BASE_DIR=$(cd $(dirname $0);pwd) **複雑なプログラムを作成したい [#s9c330b9] -オープンソースを参考にする。 -Linuxの/etc/network-scriptsとか、tomcatの起動スクリプトとか。 **実行したプログラムをエコーしたい [#qc374345] -[[bashスクリプトにおいて、 コマンドを実行しながら、そのコマン… - 人力検索はてな:http://q.hatena.ne.jp/1319616956]]にあるように -x オプションを試用する。 #!/bin/sh -x set -x *トラブルシューティング [#jc21d146] **echo -nがきかない [#e7468494] -[[少しハマったシェルスクリプト by yota.log:https://ie.u-ryukyu.ac.jp/e095708/archives/768]]にあるようにMacだとだめらしい。 ** "$@" != ""がエラーになる [#s33a4e3b] -[[シェルスクリプトでの$@の罠:http://rcmdnk.github.io/blog/2014/06/25/computer-bash/]]に書いてあること。 -以下のスクリプトを実行するとき、「./atmark.sh a」はいいけど、引数なしor2個以上の引数でエラーとなる。 #pre{{ #!/usr/bin/env bash if [ "$@" != "" ];then echo "$@" else echo empty fi }} -これは"$@"が次のように展開されるため。 "$1" "$2" "$3" -つまり、if [ "$@" = "" ];thenが、if [ "" = "" ];thenとなったりするため。