LoginSignup
4417
4545

More than 5 years have passed since last update.

初心者向け、「上手い」シェルスクリプトの書き方メモ

Last updated at Posted at 2015-02-01








 :sparkles:

 : ()



: ()0()
使
/使

()

: > foo.log # ファイルを 0 バイトで上書き

: 


便

# $foo が $bar より大きければ 0 、そうでなければ 1 を $baz に代入する。
[ $foo -ge $bar ] && baz=0 || baz=1

 [] if使
 0 1
 [] =
=

 使 @FKU 

 if

 if
# $foo が $bar より大きければ 0 、そうでなければ 1 を $baz に代入する。
if [ $foo -ge $bar ]; then
  baz=0
else
  baz=1
fi

比べてみるとその差がわかりますね。

変数のデフォルト値を指定

変数を参照した時、もしその変数が未定義だったり、空文字扱いだった場合に、
別の何かをデフォルト値として設定したいという事、プログラミングではよくありますよね。
シェルスクリプトでも、やっぱり同じことがやりたくなって調べた結果、以下の様にするとできました。

# $foo に $bar を代入。但し $bar が未定義だった場合は 0 を代入
foo=${bar:-0}

ちなみに、 - の部分を = に変える事で、 $bar 自身も上書きすることができます。

# $bar が未定義だった場合、 $foo にも $bar にも 0 を代入
foo=${bar:=0}

 : 

 @n0kada 







使

git/



使
script_dir_path=$(dirname $(readlink -f $0))

ただBSDやOSX等ではreadlinkの実装が異なるようなので、代わりに coreutils の greadlink (GNU readlink) を利用すると良いそうです。

script_dir_path=$(dirname $(greadlink -f $0))

 
@yasuhiroki  @hayamiz  @umiyosh 

 $0 使

 dirname  readlink -f 

/ trap


@s-wakaba 

ShellScript

Ctrl+C 退

 trap 
trap

 Ctrl-C 
trap "rm /tmp/temporary-file" 0

ちょっと実験してみたところ、 trap は同じスクリプト上では、同じシグナルに対して2つ以上置いても1つしか実行されない?ような気がしますので、設置するときは後処理を一つのコマンドの中に書いてしまうのがいい気がしました(間違ってたら教えてください:bow:)。この時、関数を作ってそれを呼び出すようにしてもいいのですが、自分は文字列内で以下のように書いてしまうのが簡単だと思いました(一応 bash 上では動作を確認しました。)

trap "
  mv /tmp/swap-file original-file
  rm /tmp/target-file
" 0

trap 
 trap  - UNIX & Linux  



Linux -- 


/ mktemp


 @s-wakaba 

mktemp  / 
 /tmp 
mktemp / 使 
temp_file=$(mktemp) # /tmp 配下にランダムな名前のファイルが作成される。 例: /tmp/tmp.C3N9Ng6IaU
temp_dir=$(mktemp -d) # -d を付けることでディレクトリ作成となる。 例: /tmp/tmp.wDOVMXVcio

これを上の trap コマンドと併用して利用することで、そのシェルスクリプトが動作している間だけ生きているファイル/ディレクトリを作成することができます!

# 一時ディレクトリ/ファイルを作成する。
temp_file=$(mktemp)
temp_dir=$(mktemp -d)

# 後始末を定義
trap "
rm -f $temp_file
rm -rf $temp_dir
" 0


Bash 


  shebang  set  @magicant  @syohex 

Bash 便
 set 



使 set -eux 

-e


1


 -e  
 



set -e
ls /path/to/file # ls コマンドでファイルが見つからない場合この時点でエラーとなる
cat /path/to/file # 上記でエラーとなった場合この処理が実行される前にスクリプトが中断される。

先ほどの参考演算子の項で説明した通り、条件式はそれ単発で記述すると、
その真偽値によって成功/失敗扱いとなるので、
以下のようにスクリプト内の要所要所に以下のような条件式をおいてあげるだけで、
事前チェック => 偽なら即中止といった処理を実現できます。

set -e

# 〜 中略 〜

[ $hoge -ge $fuga ] 

また、スクリプトの最後を上記のような条件式にすることで、特定の条件を満たしたかどうかで、
そのスクリプト自体の終了ステータスを調整できます。

-u

-u は、未定義の変数に対して読み込み等を行おうとした際に、きちんとエラーとして扱ってくれます。
java でいうところの NullPointerException 的な感じですね!

これを先ほどの : コマンドや -e オプションと組み合わせると、とてもシンプルに引数のチェック等ができます。

set -eu
# 引数が3つ渡されていなければスクリプト実行中止
: $1 $2 $3




 $1 $2 $3  $1 shell
: 
 " 

bash
./foo.sh: 行 2: $1: 未割り当ての変数です

()

-x


 -x 




 @melpon 



JenkinsJob


JenkinsJob -x 

 bash -x foo.sh 
 set -x 使

: -x 


-x 便


 :bow:




 : 
 : 

: ここにコメントが書ける、コンソールに出力される。

: "特殊な記号等を利用するときはクォーテーションで括る(| や & 等)"

: "
こうすれば
複数コメントも書ける。
ちゃんと改行もされて出力される。
"

: 
0

-x 


set 便
 set +x  set +eu  -  + 
 set -eu 
set -eux

# 中略

set +u # 一時的に -u オプションを無効化。

foo=$1 # この $1 は未定義かもしれないが、未定義でもエラーとならない。
echo $foo

set -u # -u オプションを元通り付与し直す。

# 以降の処理

便利ですね!

まとめ

シェルスクリプト…奥が深いッ…!
楽しい…!!

4417
4545
27

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

4417
4545