bash - array (indexed array)

### bash array

bash では、他のプログラミング言語と同様に array（配列）を使用することが出来ます。ここでは、RHEL8 を例に取り、代表的な array の操作方法をご紹介します。
bash で array と呼ぶ場合は、暗黙的に indexed array を指すことがほとんどです。associative array（連想配列）を作成することもできますが、ここでは割愛します。
```shell
$ cat /etc/redhat-release
Red Hat Enterprise Linux release 8.8 (Ootpa)

$ bash --version
GNU bash, version 4.4.20(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
```

#### Create array
以下のような方法で array を作成することが出来ます。ここでは、A B C D の4つの array を作成してみます。
```shell
$ declare -a A
$ B=(0 1 2 3 4)
$ declare -a C=(a b c d e)
$ D[1]="DD"
```
`declare -p` を使用して変数が array であることを確認することができます。
```shell
$ declare -p A B C D
declare -a A
declare -a B=([0]="0" [1]="1" [2]="2" [3]="3" [4]="4")
declare -a C=([0]="a" [1]="b" [2]="c" [3]="d" [4]="e")
declare -a D=([1]="DD")
```
ファイルからの入力でも array を作成することが出来ます。以下のファイルを使用してみます。
```shell
$ cat input.txt
date
ls -l
echo "Test Message"
echo "$HOME"
```
```shell-session
$ declare -a FILE_A=( $(cat input.txt) )
$ FILE_B=( "$(cat input.txt)" )

$ IFS=$'\r\n' GLOBIGNORE='*'
$ FILE_C=( $(cat input.txt) )

$ readarray -t FILE_D < input.txt

$ declare -p FILE_A FILE_B FILE_C FILE_D
declare -a FILE_A=([0]="date" [1]="ls" [2]="-l" [3]="echo" [4]="\"Test" [5]="Message\"" [6]="echo" [7]="\"\$HOME\"")
declare -a FILE_B=([0]=$'date\nls -l\necho "Test Message"\necho "$HOME"')
declare -a FILE_C=([0]="date" [1]="ls -l" [2]="echo \"Test Message\"" [3]="echo \"\$HOME\"")
declare -a FILE_D=([0]="date" [1]="ls -l" [2]="echo \"Test Message\"" [3]="echo \"\$HOME\"")
```
ホワイト・スペースを含むファイルの各行を array の要素に代入する場合は、FILE_C や FILE_D の例が使用できます。
```shell
$ echo ${FILE_A[1]}
ls
$ echo ${FILE_B[1]}

$ echo ${FILE_C[1]}
ls -l
$ echo ${FILE_D[1]}
ls -l
```
#### Manipulate array
代表的な配列要素（element）の操作には、以下があります。
```shell
$ declare -p FILE_D
declare -a FILE_D=([0]="date" [1]="ls -l" [2]="echo \"Test Message\"" [3]="echo \"\$HOME\"")
```
```shell
# Number of Elements
$ echo ${#FILE_D[@]}
4

# Index List
$ echo ${!FILE_D[@]}
0 1 2 3

$ for I in ${!FILE_D[@]}; do echo "$I : ${FILE_D[$I]}" ; done
0 : date
1 : ls -l
2 : echo "Test Message"
3 : echo "$HOME"

# Get All Elements
$ echo ${FILE_D[@]}
date ls -l echo "Test Message" echo "$HOME"
$ echo ${FILE_D[*]}
date ls -l echo "Test Message" echo "$HOME"

# Get Specific Elements
$ echo ${FILE_D[1]}
ls -l
$ echo ${FILE_D[-3]}
ls -l

$ expr 5 - 3
2
$ echo ${FILE_D[((5-3))]}
echo "Test Message"
$ echo ${FILE_D[5-3]}
echo "Test Message"
$ echo ${FILE_D[2]}
echo "Test Message"

# Get Elements with Slice #1
$ echo ${FILE_D[@]:-2}
date ls -l echo "Test Message" echo "$HOME"
$ echo ${FILE_D[@]:-1}
date ls -l echo "Test Message" echo "$HOME"
$ echo ${FILE_D[@]:0}
date ls -l echo "Test Message" echo "$HOME"
$ echo ${FILE_D[@]:1}
ls -l echo "Test Message" echo "$HOME"
$ echo ${FILE_D[@]:2}
echo "Test Message" echo "$HOME"
$ echo ${FILE_D[@]:3}
echo "$HOME"
$ echo ${FILE_D[@]:4}

# Get Elements with Slice #2
$ echo ${FILE_D[@]:-2:1}
date ls -l echo "Test Message" echo "$HOME"
$ echo ${FILE_D[@]:-1:1}
date ls -l echo "Test Message" echo "$HOME"
$ echo ${FILE_D[@]:0:1}
date
$ echo ${FILE_D[@]:1:1}
ls -l
$ echo ${FILE_D[@]:2:1}
echo "Test Message"
$ echo ${FILE_D[@]:3:1}
echo "$HOME"
$ echo ${FILE_D[@]:4:1}

# Get Elements with Slice #3
$ echo ${FILE_D[@]:-2:10}
date ls -l echo "Test Message" echo "$HOME"
$ echo ${FILE_D[@]:-1:10}
date ls -l echo "Test Message" echo "$HOME"
$ echo ${FILE_D[@]:0:10}
date ls -l echo "Test Message" echo "$HOME"
$ echo ${FILE_D[@]:1:10}
ls -l echo "Test Message" echo "$HOME"
$ echo ${FILE_D[@]:2:10}
echo "Test Message" echo "$HOME"
$ echo ${FILE_D[@]:3:10}
echo "$HOME"
$ echo ${FILE_D[@]:4:10}

# Get Elements with Slice #4
$ echo ${FILE_D[@]:0:-1}
-bash: -1: substring expression < 0
$ echo $?
1

# Add Elements
$ FILE_D[10]="Additional Element"
$ declare -p FILE_D
declare -a FILE_D=([0]="date" [1]="ls -l" [2]="echo \"Test Message\"" [3]="echo \"\$HOME\"" [10]="Additional Element")
$ echo ${!FILE_D[@]}
0 1 2 3 10

# Delete Elements
$ unset FILE_D[1]
$ declare -p FILE_D
declare -a FILE_D=([0]="date" [2]="echo \"Test Message\"" [3]="echo \"\$HOME\"" [10]="Additional Element")
$ echo ${!FILE_D[@]}
0 2 3 10

# Delete Array
$ unset FILE_D
$ declare -p FILE_D
-bash: declare: FILE_D: not found
$ echo $?
1
```