Shellの基本を学ぶ（６）パラメータ

# Special Variables

## Positional Parameters

`$1, $2` など９以上は、ブレースを使う`${10},${20}`。`$0` は、スクリプトのファイル名。

## `$@`
`$@` は全ての要素を表す。`$1 $2 $3 ...$N`と同じ。ちなみにダブルクオートでくくると、`"$1" "$2" "$3".. "$N"`と同じ扱いになる。

## `$*`

`$1 $2 $3 .. $N` と同じだが、ダブルクオートをつけると、`"$1 $2 $3 .. $N"` と同じになる。この振る舞いんはあまり求められないので、通常は `$@`を使う

## `$#`

シェルファイルへの引数の数。

## サンプル

_paramtest_

```bash
#!/bin/bash

echo "Filename: $0"
echo "Number of parameters: $#"
for a in "$@"; do
  echo $a;
done
```

## 実行結果

`$0`はファイル名で、相対パスで書いた場合は、相対パス、シンボリックリンクでもシンボリックリンク名、絶対パスなら絶対パス。ちなみに、PATHの上に置いて実行した場合、絶対パスになる。

```bash
$ ./paramtest
Filename: ./paramtest
Number of parameters: 0
invincible:file ushio$ ./spt
Filename: ./spt
Number of parameters: 0
```

ループだが、`"$@"`のようにダブルクオートをつけない場合は、次のようになる。

```bash
$ ./paramtest a b "c d" e
Filename: ./paramtest
Number of parameters: 4
a
b
c
d
e
```
スペースを解釈してしまう。だから、上記のサンプルのようにダブルクオートをつけると認識してくれる。

```bash
$ ./paramtest a b "c d" e
Filename: ./paramtest
Number of parameters: 4
a
b
c d
e
```

ちなみに、`"$*"` を使うと

```
a b c d e
```

になる。

# Shift

最初のパラメータを取り除く

_create_script_

写経一部改変で、シェルファイルを作るプログラム。ループの中で、変数をShiftで取り除いてループさせている。忘れてたけど、`type` はファイルをどのように解釈するかを返すコマンドで、ファイルの存在チェックによく使われる。通常は、ファイルのパスを返す。

```bash
# Create a new bash script with giving permission

[[ $1 ]] || { echo "Arguments missing" >&2; exit 1; }

declare open_editor=""

[[ $# -eq 1 ]] && open_editor="true"

declare -r bindir="$(pwd)/bin"

if [[ ! -d $bindir ]]; then
  if mkdir "$bindir"; then
    echo "created ${bindir}" >&2
  else
    echo "Could not create ${bindir}." >&2
    exit 1
  fi
fi

while [[ $1 ]]; do
  scriptname="$1"
  filename="${bindir}/${scriptname}"

  if [[ -e $filename ]]; then
    echo "File ${filename} already exists" >&2
    shift
    continue
  fi

  if type "$scriptname" > /dev/null 2>&1; then
    echo "There is already a command with name ${scriptname}" >&2
    shift
    continue
  fi

  echo "#!/bin/bash" > "$filename"
  chmod u+x "$filename"

  shift
done

if [[ $open_editor ]]; then
  echo "opening..."
  if [[ $EDITOR ]]; then
    $EDITOR "$filename"
  else 
    echo "Can't open $filename"
  fi 
fi

exit 0
```

# getops

getopts はポジショナルパラメータをパースするために使われる。`OPTINT` という変数は、オプションではない最初の引数が入る。名前は`?` になる。`?`はオプションが見つからない場合で、`:` は、オプションの引数が見つからない時


_count_

```bash
#!/bin/bash

# This script prints a range of numbers
# Usage: count [-r] [-b n] [-s n] stop
# -b gives the number to begin with (default: 0)
# -r reverses the count
# -s sets step size (default: 1)

declare reverse=""
declare -i start=0
declare -i step=1



while getopts "b:s:r" opt; do 
  case $opt in
    r)
      reverse="yes"
      ;;
    b)
      [[ ${OPTARG} =~ ^[0-9]+$ ]] || { echo "${OPTARG} is not number" >&2; exit 1; }
      start="${OPTARG}"
      ;;
    s)
      [[ ${OPTARG} =~ ^[0-9]+$ ]] || { echo "${OPTARG} is not number" >&2; exit 1; }
      step="${OPTARG}"
      ;;
    :)
      echo "Option -${OPTARG} is missing an argument"
      exit 1
      ;;
    \?)
      echo "Unknown option: -${OPTARG}" >&2
      exit 1
      ;;
  esac
done

shift $(( OPTIND -1 ))

[[ $1 ]] || { echo "Argument is missing" >&2; exit 1; }
declare end="$1"

if [[ ! $reverse ]]; then
  for (( i=start; i <= end; i+=step )); do
    echo $i
  done
else
  for (( i=end; i >= start; i-+step )); do
    echo $if
  done
fi

exit 0


```

### 実行結果

$OPTARG は、オプションの値が引き渡って来る。

```bash
$ count -s
//Users/ushio/Codes/Bash/bin/count: option requires an argument -- s
invincible:Bash ushio$ count -s 2 10
0
2
4
6
8
10
 count -b 11 -s 2 22
11
13
15
17
19
21
$ count -b
OPTARG: b
Option -b is missing an argument
$ count -b 1 -q 2  22
OPTARG: 1
OPTARG: q
Unknown option: -q
```

ちなみに、最初実施した時に想像した通りにならなかった。本来 `":b:s:r"`のところを`"b:s:r"` と記述していたため。

* [getopts](https://ss64.com/bash/getopts.html)