bash シェルのスクリプトで現在の実行行/呼び出し行の取得（行番号の取得）

> ファイル上の**現在の行番号を Bash のスクリプト内で取得**したい。

例えば Perl や PHP の「`__LINE__`」や Golang の `_, _, line, _ := runtime.Caller(0)` のように。

他の言語では実行行の取得は分かっていたのですが、「シェルの場合は何だっけ」と Qiita 記事に絞って[「`site:qiita.com シェル 現在の実行行 行番号 取得`」とググって](https://www.google.co.jp/search?q=site%3Aqiita.com+%E3%82%B7%E3%82%A7%E3%83%AB+%E7%8F%BE%E5%9C%A8%E3%81%AE%E5%AE%9F%E8%A1%8C%E8%A1%8C+%E8%A1%8C%E7%95%AA%E5%8F%B7+%E5%8F%96%E5%BE%97)もすぐに見つからなかったので、自分のググラビリティとして。

## TL; DR <sub><sup><sub><sup>（今北産業）</sup></sub></sup></sub>

1. シェル変数の「`$LINENO`」を使う。ラインナンバーの略。
2. 関数の「呼び出し元の実行行」を取得したい場合は「`$BASH_LINENO`」
3. 動くサンプルをおくれ。

  ```bash:sample_lineno.sh
  #!/bin/bash
  
  echo $LINENO
  echo $LINENO
  ```

  ```shell-session:実行結果
  $ ./sample_lineno.sh
  3
  4
  ```

  ```bash:sample_bash_lineno.sh
  #!/bin/bash
  
  hoge () {
      echo "Called from line:${BASH_LINENO[0]}"
  }
  
  hoge
  hoge
  ```

  ```shell-session:実行結果
  $ ./sample_bash_lineno.sh
  Called from line:7
  Called from line:8
  ```

- [オンラインで色々な動作を見る](https://paiza.io/projects/xW0g5zcysF5E84H5g2x0Xw) @ paiza.IO

### 動作確認済み環境

- macOS HighSierra（OSX 10.13.6）
- `bash --version`: `GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)`

## TS; DR <sub><sup><sub><sup>（用途に関するコマケーこと）</sup></sub></sup></sub>

実行行の取得は、**一般的には LOG 出力に使うことが多い**と思います。しかし、今回は終了ステータスのコードを実行行にしたかったのです。

つまり、スクリプトを `exit` する際の "`0`"（正常終了）以外の場合、通常はエラー番号（エラーコード）を "`1`" や独自のエラーコードにするところを、「**`exit` した行」にしたかった**のです。

```bash:sample.sh
#!/bin/bash

dir_curr=$(cd $(dirname $0); pwd)

# Make temp directory
# -------------------
echo -n 'Now creating temporary directory ... '
dir_temp=$(mktemp -d)
if [ $? -gt 0 ]; then
    echo ' NG'
    echo '* Error while creating temp directory.'; exit $LINENO
fi
echo 'OK'

# Moving to temp directory
# ------------------------
echo -n 'Now changing work directory to temporary ... '
cd $dir_temp
if [ $? -gt 0 ]; then
    echo ' NG'
    echo '* Error while changing work to temp directory.'; exit $LINENO
fi
echo 'OK'

exit 0
```

PHP や Golang などからシェル・スクリプトを外部コマンドとして実行した際、問題があった場合に標準エラー出力（`STDERR`）と共に、エラー番号に意味を持たせたかったのです。

しかし、**横着なため管理しきれず**、「どうせソースを見に行くんだから行番号の方が楽でいいや」と**「エラー番号 ＝ エラーで抜けた行」に統一**することにしました。`_(:⁍」 )_`

<font color=red>**注意点**</font>として、**bash の終了ステータス番号は１バイト**、つまり 0-255 の整数です。255 を越えると 0 から再度カウントされた値が出力されます。

つまり、`$EXIT_NUM % 256` と 256 で [`mod`（剰余）](https://ja.wikipedia.org/wiki/%E5%89%B0%E4%BD%99%E6%BC%94%E7%AE%97) されて出力されるのです。

```shell-session:第１引数を終了ステータス番号として「exit」するだけのスクリプトでテスト
$ # テスト・スクリプト
$ cat sample.sh
#!/usr/bin/env bash
exit $1

$ # テスト
$ ./sample.sh 10 ; echo $?
10

$ ./sample.sh 255 ; echo $?
255

$ ./sample.sh 256 ; echo $?
0

$ ./sample.sh 257 ; echo $?
1
```

このように、「エラー番号＝終了行」とする手法を使う場合、スクリプトは 255 行以内に抑える必要があります。偶然にも 256 行目でエラーが発生しても `0` となり正常終了扱いになったり、256 行目以降では追跡できなくなるからです。

そのため私の場合、**スクリプトは 256 行以上になるならファイルをわける**という方針でカバーしています。

256 行以内に抑えることが難しい場合は、別のスクリプトにわけてメインのスクリプトから呼び出すことも可能です。

### `source` でスクリプトを `include` しても動作する

別のスクリプト・ファイルにわける場合は、`source <inclueするファイルのパス>` で可能です。その際に、`include` する側は `$BASH_LINENO` で「呼び出し元の行番号」を取得できます。

```bash:sample1.sh
function function1(){
  echo $BASH_LINENO
}
```

```bash:Main.sh
#!/bin/bash

source sample1.sh
function1
```

```shell-session
./Main.sh
4
```

- [オンラインで色々な動作を見る](https://paiza.io/projects/xW0g5zcysF5E84H5g2x0Xw) @ paiza.IO