シェルスクリプト覚え書き

# 今日の日付を取得

書式指定ができる（以下の場合は8桁）

```bash:
date '+%Y%m%d' # 8桁
date '+%Y-%m-%d %H%M%S'　# 時刻まで含む
```

# ディレクトリの名前を取得

今いるディレクトリの名前のみが必要な場合は、

```bash:
current_dir=`pwd -P | rev | cut -f 1 -d / | rev`
```


pathを取得して、その中にリスト中のディレクトリ名が含まれているかどうか判断する (何も考えずにディレクトリ構造を作ってしまったが、変更が面倒なときに有用)。

```bash:
explist=(mh lgm)
if [[ $(printf '%s\n' "${explist[@]}" | grep -qx "${exp}"; echo -n ${?} ) -eq 0 ]]; then
	workdir=./past/${exp} 
    else
	workdir=./${exp}
fi
```

# lsで例外処理

特定の条件を除外してlsしたい場合

```bash:
ls --ignore={"*.nc", "*.csv"}
```

拡張子が`.nc`と`.csv`のファイルが取り除かれる。

# forループでループする数字の桁を揃える

3桁に揃えたい場合。

```bash:sample.sh
for i in `seq -f %03g 1 100`
do
        hogehoge
done
```

# 複数行のecho

いちいちテキストファイルに出力しなくてもいいんです。

```bash:sample.sh
{
      echo 0 1
      echo 0 4
}
```

とすると

```bash:
0 1
0 4
```

と出力。

# オプションを定義

スクリプト実行時にオプションをつけたい場合は、コマンドラインで

```bash:
bash sample.gmt -I [filename] -O
```

スクリプト中では、

```bash:sample.gmt
CMDNAME=`basename $0`
while getopts I:O OPT # オプションに引数が必要な場合は":"をつける
do
     case ${OPT} in 
     # 該当するものがあるか、上から順にチェック
     "I"  ) FLAG_I="TRUE"     ; filename=${OPTARG}          ;;
     "O"  ) FLAG_O="TRUE"                                    ;; 
     *    ) echo "Usage: ${CMDNAME} [-I filename] " ; exit ;;
     # 該当するものがなかった場合、終了
     esac
done
```

# ループ内変数をループ外で使う

以下のようにしてしまうと、ループでの計算結果が反映されない

```bash:sample_error.sh
i=0
cat ${file} | while read dummy num
do
      if [ $num -lt 0 ] ; then
            i=$((i+num))
      fi
done
echo $i
```

パイプをやめるとうまくいった

```bash:sample_correct.sh
i=0
for num in `awk '{print $2}' ${file}`
do
      if [ $num -lt 0 ] ; then
            i=$((i+num))
      fi
done
echo $i
```

# 小数演算

exprコマンドなどでは、整数演算ができるが、小数演算ができない。そこで、

```bash:
echo "3.5+1.2" | bc
```

とすれば、

```bash:
4.7
```

と返ってくる！桁数を指定したい場合は、

```bash:
echo "scale=3;10.0/3.0" | bc
```

とすれば、小数点以下3桁で計算されて、

```bash:
3.333
```
# if文の条件判定

|演算子|意味|
|---|---|
|`-eq`  | equal |
|`-ne`  | not equal |
|`-lt`  | less than |
|`-le`  | less than or equal |
|`-gt`  | greater than |
|`-ge` |  greater than or equal |
|`-e` | check existance |
|`-d` | check directory |
|`-f` | check file      |
|`-n` | not empty       |

# if文で小数の大小判定をしたい

直接if文のなかで処理できないので、工夫が必要

```bash:sample.sh
result=`echo "$x >= $y" | bc` ; echo ${result}
if [ ${result} -eq 1 ]; then
       echo "$x >= $y"
       hogehoge
else
       echo "$x < $y"
       piyopiyo
fi
```

# 行番号をつけて出力

```bash:sample.sh
nl -w $num ${filename} > ${outfile} #numは桁数
```
# 画像サイズを変更 (convert)

画像サイズを変えたいとき、

```bash:
convert ${infile} -resize ${width}x${height} ${outfile}
```

タテヨコ比を無視したいときは、!をつければよい

```bash:
convert ${infile} -resize ${width}x${height}! ${outfile}
```

# 白背景の透過

```bash:
convert original.png -fuzz 10% -transparent white transparent.png
```

[参考](https://travelingresearcher.com/entry/2015/11/15/164011)

# 画像の結合

```bash:
convert -append figure1.png figure2.png figure3.png output.png #縦
convert +append figure1.png figure2.png figure3.png output.png #横
montage -tile [横]x[縦] -geometry 100% *.png output.png # 縦横
```

[参考](https://qiita.com/foo9/items/f930358d379c0fa9ceb5)

# アニメーション作成

`-delay`でタイムステップを指定(1/100秒単位)。画像ファイルは数字で名前振っておくと楽。

```bash:
 convert -delay 30 *.png output.gif
```

# sedによる行の取り扱い

filenameの8行目を削除

```bash:
sed -i '8d' ${filename}
```

filenameの1行目に**TEXT label**を追加(スペースがある場合は、`"`で囲む)

```bash:
cat ${filename} | sed -e "1iTEXT label" > ${outfile}
```

# awkによる列の取り扱い

filenameの1列目が2だったときに2列目の値を返す

```bash:
awk '{if($1==2){print $2}}' ${filename}
```

filenameの1列目がstrだったときに2列目の値を返す

```bash:
awk -v a="${str}" '{if($1==a){print $2}}' ${filename}
```

filenameの1列目が2だったときにn列目の値を返す

loopの中などでつかう

```bash:
awk -v n=${loopno} '{if($1==2){print $n}}' ${filename}
```

返した値を他の変数に読ませたいときは、

```bash:
result=`awk '{if($1==2){print $2}}' ${filename}`
```

filenameの2行目までをoutfileへ出力

```bash:
awk 'NR<=2' ${filename} > ${outfile}
```

filenameの2行目から5行目をoutfileへ出力

```bash:
awk 'NR==2,NR==5' ${filename} > ${outfile}
```

filenameの末尾の行だけをとりだす

```bash:
awk '{print $NF}' ${filename} > ${outfile}
```

出力結果の桁を指定

```bash:
awk '{printf "書式\n", $NF}' ${filename} > ${outfile}
```

# プロセスIDをまとめてkillしたい

```bash:
list=($(ps -f |awk '{{print $2}}'))
echo ${list[@]}
```
問題なさそうだったら、`kill ${list[@]}`

# 例外ファイルを指定してまとめて削除したい

`RSTA`と`SYSIN`以外のファイルやディレクトリを削除するには、

```bash:
ls | grep -v "RSTA\|SYSIN" | xargs rm -r
```

# 書式制御文字一覧

|演算子|意味|
|---|---|
| `%d`|    十進整数、`%i`も使用可|
| `%e`|    指数形式、`%E`の場合Eが大文字で出力される|
| `%f`|    小数点を使用した形式、桁数は`%4.3f`のように指定する|
| `%g`|    `%f`か`%e`で短くなる方、`%G`の場合`%E`同様Eを大文字で出力|
| `%o`|    符合なしの八進数|
| `%x`|    符合なしの十六進数、'%X'の場合アルファベットを大文字時で出力|
| `%c`|    ASCIIキャラクタ、例えば'65'をいう数値を'A'と出力|
| `%s`|    文字列|

---

# 関連ページ
- [便利なコマンドのくみあわせ](https://qiita.com/kanonundgigue/items/859142f21407e320e7df)