&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となったりするため。

トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS