忘れがちなシェルスクリプト

# ■ インタプリタ指定(シバン)
~~~sh
#!/bin/sh

#!/bin/bash
~~~

【オプション】
```-e``` ：終了ステータスが1で停止
```-x``` ：実行コマンド・変数値表示
```-v``` ：実行コマンド表示

# ■ 構文

## if文
~~~sh
cnt=0
if [ $cnt -eq 0 ]
then
  echo "value=0"
elif [ $cnt -eq 1 ]
then
  echo "value=1"
else
  echo "value!=0 or 1"
fi
~~~

## case文

~~~sh
case $# in
  0)
    cnt=0
    ;;
  1)
    cnt=$1
    ;;
  *)
    cnt=$2
    ;;
esac
~~~

## for文

~~~sh
for file in *
do
  if [ ! -e $file ]
  then 
    break
  fi
  echo $file
done
~~~

~~~sh
for((i=1; i<=10; i++)){
  echo $i
}
~~~

## while文

~~~sh
while [ $cnt -le 10 ]
do
  echo $cnt
  if [ $cnt -eq 5 ]
  then
    break
  fi
done
~~~

# ■ 条件式

## testコマンド

~~~sh
if [ $# -eq 0 ]
then
  echo "引数なし"
fi
~~~

【真になる条件】
```A -eq B``` ：数値A == 数値B(equal to)
```A -ne B``` ：数値A != 数値B(not equal to)
```A -lt B``` ：数値A < 数値B(less than)
```A -le B``` ：数値A <= 数値B(less than or equal to)
```A -gt B``` ：数値A > 数値B(greater than)
```A -ge B``` ：数値A >= 数値B(greater than or equal)
```A -a B``` ：条件A and 条件B
```A -o B``` ：条件A or 条件B
```! A``` ：条件Aが偽
```A = B``` ：文字列Aと文字列Bが一致
```A != B``` ：文字列Aと文字列Bが不一致
```-d A``` ：ファイルAがディレクトリ
```-e A``` ：ファイルAが存在する

# ■ シェル関数

## 同一ファイル内のシェル関数実行
~~~sh:output.sh
cut_2-3()
{
  echo $1 | cut -c 2-3 
}

output="0123456789"
cut $output

echo $1 
~~~

~~~shell-session
$ bash output.sh 5
12
5
~~~

## 別ファイルのシェル関数実行

~~~sh:cut.sh
func_cut()
{
  echo $1 | cut -c 2-3 
}
~~~

~~~sh:disp.sh
. cut.sh
input="0123456789"
func_cut $input
value=`func_cut $input`
echo `expr $val + 1`
~~~

~~~shell-session
$ bash disp.sh
12
13
~~~

# ■ 標準出力へ出力

## printf-フォーマット指定して出力
~~~shell-session
$ answer=0xffffffff
$ printf '16進数では0x%xです。\n10進数では%dです。\n' "$answer" "$answer"
16進数では0xffffffffです。
10進数では4294967295です。
$ answer=0.1234
$ printf '小数点では%.3fです。' "$answer"
小数点では0.123です。
~~~

```%d``` ：符号付き10進数
```%u``` ：符号なし10進数
```%x``` ：16進数
```%s``` ：文字列
```%f``` ：浮動小数点
```%e``` ：浮動小数点(指数表現)
```%8d``` ：8文字分のスペースで10進数表示(右詰め)
```%-8d``` ：8文字分のスペースで10進数表示(左詰め)
```%08x``` ：足りない分は0をつけて8桁で16進数表示

## echo - メッセージを出力

~~~shell-session
$ answer="0xffff"
$ echo '答えは'"$answer"'です。'
答えは0xffffです。
~~~

~~~shell-session:10進数⇒16進数
$ echo "obase=16;ibase=10;65535" | bc
FFFF
~~~

~~~shell-session:16進数⇒10進数
$ echo "obase=16;ibase=10;FFFF" | bc
65535
~~~

~~~shell-session:16進数⇒2進数
$ echo "obase=2;ibase=16;FF" | bc
11111111
~~~

~~~shell-session:2進数⇒16進数
$ echo "obase=16;ibase=2;01011101" | bc
5D
~~~

# ■ 標準入力から読み込み
## read-キーボードから入力
~~~shell-session
$ echo -n "Input Data (ex. xxx) --->"
$ read inuptData
$ echo ${inputData}
~~~

# ■ 計算

## 16進数の計算

~~~shell-session
$ value=$((0x20 + 0x10))
$ echo $value
48
~~~

~~~shell-session
$ value="a0"
$ echo $((0x$value * 2))
320
~~~

~~~shell-session
$ echo "obase=10;ibase=16;F0 + FF" | bc
495
$ val=`echo "obase=10;ibase=16;F0 + FF" | bc`
$ echo $val
510
~~~

## 下位1Byte取得

~~~shell-session
$ source=257
$ output=`expr $source % 256`
$ echo $output
1
~~~

## 桁数取得
~~~shell-session
$ count=10000
$ echo "length($count)" | bc
5
~~~

# ■ 組み込みコマンド

## 変数の値を標準入力に設定

~~~shell-session
$ output="012345"
$ echo $output | cut -c 3-4
23
~~~

# ■ クォート

## 特殊文字の打ち消して文字列使用

~~~shell-session:シングルクォート
$ echo 'HOME=$HOME'
HOME=$HOME
~~~

## パラメータ展開をして文字列使用

~~~shell-session:ダブルクォート
$ echo "HOME=$HOME"
HOME=/home/vagrant
~~~

~~~shell-session
$ dir0="/home"
$ dir1="/ubuntu"
$ cd "${dir0}/vagrant${dir1}"
$ echo `pwd`
/home/vagrant/ubuntu
~~~

## 1文字分の特殊文字の打消し

~~~shell-session:バックスラッシュ
$ echo \*
*
~~~

## コマンドの標準出力を引数として取り込み

~~~shell-session:バッククォート
$ dir="/home/vagrant"
$ name=`basename $dir`
$ echo $name
vagrant
$ name=`grep "test" output.txt | cut -c 2-4`
$ mkdir `cat output.txt | grep "A"`
~~~



# ■ リダイレクト

## 標準出力を非表示にする

~~~shell-session
$ grep "aaa" * 1> /dev/null
~~~

## 標準エラーを非表示にする

~~~shell-session
$ grep "aaa" * 2> /dev/null
~~~

## 標準出力・エラーを非表示にする

~~~shell-session
$ grep "aaa" * > /dev/null 2>&1
~~~

# ■ 外部コマンド
## sleep - 一定時間ウエイト

~~~shell-session
$ sleep 10
$ sleep 0.1
$ sleep 10m
~~~

```s``` ：秒
```m``` ：分
```h``` ：時間
```d``` ：日

## basename - ファイル名からディレクトリ名／拡張子除去

~~~shell-session
$ name=`basename home/user/output.txt`
$ echo $name
output.txt
$ basename `pwd`
user
$ basename home/user/output.txt .txt
output
~~~

## dirname - ファイル名からディレクトリ名取り出し

~~~shell-session
$ name=`dirname home/user/output.txt`
$ echo $name
home/user/
$ dirname `pwd`
home
$ dirname home/user
home
~~~

## expr - 数値計算

~~~shell-session
$ expr 10 \* 5
50
$ cnt=`expr 10 \* \(5 + 2\)`
$ echo $cnt
70
~~~

~~~sh
if [ $count -eq `expr 500 \* 2` ]
then
  echo "一致"
fi
~~~

# ■ 特殊パラメータ

## 引数の数を表示

~~~shell-session
$ echo $#
~~~

## 引数の数が0なら終了

~~~shell-session
if [ $# -eq 0 ]; then
  exit 1
fi
~~~

## 最後の引数を表示

~~~shell-session
echo ${@:$#:1}
~~~

## 終了ステータスを表示

~~~shell-session
$ echo $?
~~~

## 実行中のシェルのプロセスIDを表示

~~~shell-session
$ echo $$
~~~

## 最後に実行したプロセスIDを表示

~~~shell-session
$ echo $!
~~~


# ■ 配列

~~~sh
array=("\[a\] one" "\[b\] two" "\[c\] three" "\[d\] four" "\[e\] five")
for((i=0; i<5; i++)){
  val=`grep "${array[$i]}" output.txt`
  echo $val
}
~~~

# ■ スクリプト起動

## バックグランドで別スクリプト起動＆終了

~~~sh
./another_script.sh &
process_id=$!

# any other operations

kill process_id
~~~

# ■ Git操作

## git diffの"+"と"-"行数を出力
~~~sh
grep -v "+++" test.diff | awk '/^+/{printf $0 "\n"}' | sed -e "s/+//g" | sed -e "s/ //g" | awk 'NF' | gawk '! /^\*/{printf $0 "\n"}'| gawk '! /^\//{printf $0 "\n"}' | wc -l | awk '{print "Add    : " $0}'
grep -v "\-\-\-" test.diff | awk '/^-/{printf $0 "\n"}' | sed -e "s/-//g" | sed -e "s/ //g" | awk 'NF' | gawk '! /^\*/{printf $0 "\n"}'| gawk '! /^\//{printf $0 "\n"}' | wc -l | awk '{print "Delete : " $0}'
~~~

# ■ その他

## カレントディレクトリのファイルに対する操作

~~~shell-session
$ ls * | while read f; do touch $f ; done
~~~

## 標準出力に対する一行単位の操作

~~~shell-session
$ grep "LOG" aaaa.txt | while read line; do printf 'result : %s\n' "$line"  ; done
$ grep "LOG" aaaa.txt | awk '{print "result : " $1}'
~~~

## 無限ループ

~~~sh
while :; do
  echo `date`
done
~~~

## 複数行のコメントアウト

~~~sh
: << '#COMMENTOUT'
ソース
#COMMENTOUT
~~~

## 複数行に区切って入力

~~~sh
printf \
"%d" $count
~~~