Bash Script の自分的まとめ

# Summary

bash script の自分的まとめ
bash script むずかしい・・・

## Environment

```shell
$ sw_vers 
ProductName:	Mac OS X
ProductVersion:	10.13.4
BuildVersion:	17E202
```

## 01. Setting of Bash

### Update bash

```shell
# 新しいbashをインストール
$ brew install bash

# インストールしたshellのパスを追加する
$ sudo vim /etc/shells
    /usr/local/bin/bash

# ターミナルのデフォルトのshellを設定する
$ chsh -s /usr/local/bin/bash

# 使われているshellの確認
$ echo $SHELL
/usr/local/bin/bash

$ echo $BASH_VERSION 
    4.4.19(1)-release
```

### Config files

| File Name     | Description                                                         |
| ------------- | :-------------                                                      |
| .bash_profile | ログイン時に1回だけ実行される。 |
| .bashrc       | シェルを起動するたびに実行される。localな感じ？|
| .inputrc      | ここはぜひとも変えておく！                                      |

```bash:.bash_profile
# いろいろ設定
# set path とか　prompt とか　completions とか
# たとえば

export EDITOR=vim

# ( language )
export LANG=en_us.UTF-8

# ( ls )
export CLICOLOR=1
export LSCOLORS=ExFxBxDxCxegedabagacad

#-------------------------------------------------------------
#  Load .bashrc
#-------------------------------------------------------------

if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi
```

```bash:.bashrc
# いろいろ
# たとえば

export MONO_GAC_PREFIX=/usr/local
export WINEPREFIX=~/.wine
export XDG_CONFIG_HOME=~/.config
export FZF_DEFAULT_OPTS='--height 40% --reverse --border --ansi'
eval "$(hub alias -s)"
[ -f ~/.fzf.bash ] && source ~/.fzf.bash
```

```bash:.inputrc
# see also: https://wiki.archlinux.jp/index.php/Readline

$include /etc/inputrc

set editing-mode vi

$if mode=vi

    set keymap vi-command
    # these are for vi-command mode
    "\C-p": history-search-backward
    "\C-n": history-search-forward
    j:history-search-forward
    k:history-search-backward

    set keymap vi-insert
    # these are for vi-insert mode
    "\C-p": history-search-backward
    "\C-n": history-search-forward
    "\C-h": backward-char
    "\C-l": forward-char

$endif

# requires >= Bash 4.3
set show-mode-in-prompt on
set show-all-if-ambiguous on
set completion-ignore-case on
# Color files by types
set colored-stats On
# Append char to indicate type
set visible-stats On
# Mark symlinked directories
set mark-symlinked-directories On
# Color the common prefix
set colored-completion-prefix On
# Color the common prefix in menu-complete
set menu-complete-display-prefix On

```

## 02. Reference of Bash

read! read! read!

```shell
$ man bash
$ info bash
```

## 03. Setting of Bash script

### Run Bash script

```shell
$ vim foo.bash
    echo $BASH_VERSION

$ bash foo.bash
    4.4.19(1)-release
```

### Run Bash script ( in Vim with vim-quickrun )

`.vimrc`は下記のようにする

```vim:.vimrc
" see also: :help ft-sh-syntax
autocmd FileType sh let g:is_bash = 1
autocmd FileType sh let g:sh_no_error = 1

let g:quickrun_config.sh = {
    \ 'command': 'bash'
\}
```

`:QuickRun`

```shell
$ vim foo.bash
    echo $BASH_VERSION

:QuickRun
    4.4.19(1)-release
```

`shebang`を書く時は下記のように書くのが無難

```shell
$ vim foo.bash
    #!/usr/bin/env bash
    echo $BASH_VERSION

:QuickRun
    4.4.19(1)-release
```

`shebang`で実行`shell`を指定できる

```shell
$ vim foo.bash
    #!/bin/bash
    echo $BASH_VERSION

:QuickRun
    3.2.57(1)-release
```

### Auto-completet

`terminal`での`auto-complete`

事前に `$ brew install git` をしておく

```bash:.bash_profile
# Bash's auto-complete is already implimented. ( requires > 4.x )
function bashComplete () {

    # Load extra complete config files
    local dir=$(brew --prefix)/etc/bash_completion.d
    for file in ${dir}/* ; do
        [ -r "$file" ] && source "$file"
    done
    unset file

}

bashComplete
```

`vim`での`auto-complete`

```vim
" 調べ中〜 (^_^;;;
```

## 04. Bash script cheatsheet

Must see: [Bash scripting cheatsheet](https://devhints.io/bash)

### Basic

#### comment

```bash
# comment line
```

#### commnad
```bash
ls                  # ls is command （コマンドはstatus codeをかえす success 0, failed others ）
ls >/dev/null 2>&1  # >/dev/null 2>&1 show gabage （表示を出力しない）
echo $?             # $? shows previous status code ( success 0, failed others )
```

#### variable, array and function

```bash
# variable
foo='
    foo
    bar
    baz
'

# array
bar=(
    foo
    bar
    baz
)

# function ( available local variables )
baz () {
    local foo=hello
    echo "${foo}"
}

# expansion $
echo "${foo}"
echo "${bar[@]}"

# run function
returnValue=$( baz )
echo ${returnValue} world
```

result

```text

    foo
    bar
    baz

foo bar baz
hello world
```

#### condition if

see also : `$ help test`
`if`は`status code`をみている

```bash
# lsコマンドが正常に終了したかどうか？
ls >/dev/null 2>&1
if [ "$?" = 0 ] ; then
    echo 'success!'
else
    echo 'failed!'
fi

# コマンドがあるかどうか？
if type foo >/dev/null 2>&1 ; then
    echo 'foo command exists!'
else
    echo 'foo command not exists!'
fi

# ファイルがあるかどうか？
if [ -e ./foo.txt ]; then
    echo "foo.txt found"
else
    echo "foo.txt NOT found."
fi

# フォルダがあるかどうか？
if [ -d ./foo/ ]; then
    echo "folder found"
else
    echo "folder NOT found."
fi
```

#### Loop ( while and for )

see also: `$ help read`

```bash
foo='
    foo     bar
    bar     bar
    baz     bar
'

echo "${foo}" |
    while read -r line
    do
        echo "${line}"
    done

for v in "${foo}"
do
    echo "${v}"
done
```

result

```

foo     bar
bar     bar
baz     bar


    foo     bar
    bar     bar
    baz     bar

```

### Quoting and IFS

```text
$ man bash
    /quoting

Quoting  is used to remove the special meaning of certain characters or
words to the shell.  Quoting can be used to disable  special  treatment
for special characters, to prevent reserved words from being recognized
as such, and to prevent parameter expansion.

$ man bash
    /ifs

The  Internal  Field  Separator  that is used for word splitting
after expansion and to split lines  into  words  with  the  read
builtin  command.   The  default  value  is  ``<space><tab><new-
line>''.
```

| Name         | Example | Exception |
| ----------   | :-----  | :-----    |
| single quote | 'foo'   | None      |
| double quote | "foo"   | $ \ \`    |
| back slash   | /$      | None      |

```bash
foo='
    foo
    bar
    baz
'

# IFSがキャンセルされる
echo "${foo}"

#
#    foo
#    bar
#    baz
#

# IFSが効いている
echo ${foo}

#foo bar baz
```


### Subshell

```shell
tmp$ cd foo/ ; ls
FSharp.Core.dll foo.exe         foo.exe.mdb     foo.fsx
foo$ pwd
/Users/callmekohei/tmp/foo

tmp$ ( cd foo/ ; ls )
FSharp.Core.dll foo.exe         foo.exe.mdb     foo.fsx
tmp$ pwd
/Users/callmekohei/tmp
```



### Positional Parameters

| position      | meaning                        |
| ------------- | -------------                  |
| $0            | file name                      |
| $@            | all parameters                 |
| "$@"          | all parameters( turn off IFS ) |
| $1            | first parameter                |
| $2            | second parameter               |

```bash
for v in $@
do
    echo "${v}"
done

echo '-----'

for v in "$@"
do
    echo "${v}"
done
```

result

```shell
$ bash foo.bash 'hello world' 'foo bar baz'

hello
world
foo
bar
baz
-----
hello world
foo bar baz
```


### Command substitution

```text
$ man bash
    /command substitution

Command substitution allows the output of a command to replace the com-
mand name.  There are two forms:

          $(command)
    or
          `command`
```

```bash
# ただのlsという文字列
foo=ls
echo "${foo}"

# ls

# ls コマンド
bar=$(ls)
echo "${bar}"

# Desktop
# Documents
# Downloads
# Library
# Movies
# Music
# Pictures
# Public
# mono64
# tmp
```