#author("2019-02-09T06:28:39+00:00","default:haikikyou","haikikyou")
Bashマニュアルから(自分が)頻繁に使用するであろう機能をピックアップしてまとめる。


#contents

* コマンド [#j1138789]

** ループ [#da0f596d]

*** until [#r0605004]

 until test-commands; do consequent-commands; done

条件が成り立つまで繰り返す。

#geshi(bash){{{
# --- commands ---

rm "job.done"

{ sleep 3 && touch job.done; } &

retry=0
until [ -f "job.done" ]
do
  sleep 1
  ((retry+=1))
  if [ $retry -gt 5 ]; then
     echo "exceeded retry max:5."
     exit 1
  fi
done
echo "success"

# --- output ---

success
}}}

*** while [#ec71bf2b]

 while test-commands; do consequent-commands; done

条件が成り立つ間繰り返す。

#geshi(bash){{{
# --- commands ---

touch "job.lock"

{ sleep 3 && rm job.lock; } &

retry=0
while [ -f "job.lock" ]
do
  sleep 1
  ((retry+=1))
  if [ $retry -gt 5 ]; then
     echo "exceeded retry max:5."
     exit 1
  fi
done
echo "job done"

# --- output ---

job done
}}}


*** for [#k816bb81]

 for name [ [in [words …] ] ; ] do commands; done
 for (( expr1 ; expr2 ; expr3 )) ; do commands ; done

wordsの数繰り返す。&code(){(( ))}; は、他のプログラミング言語同様の構文。~
expr1が最初に評価され、expr2がゼロになるまで、commandsを繰り返し評価する。expr2がゼロでない場合は、expr3が評価される。

#geshi(bash){{{
# --- commands ---

for w in {localhost,192.168.3.4}; do
  echo "$w"
done

# --- output ---

localhost
192.168.3.4


# --- commands ---

for ((i=0; i < 5;i++)); do
  echo $i
done

# --- output ---

0
1
2
3
4
}}}


&label(warn){参考}; https://www.gnu.org/software/bash/manual/bash.html#Looping-Constructs
** 条件 [#hd3bad84]

*** if [#l6343e8e]

#geshi(bash){{{
if test-commands; then
  consequent-commands;
[elif more-test-commands; then
  more-consequents;]
[else alternate-consequents;]
fi
}}}

ifの条件式には、コマンドやBashの条件式(-aや-fなど)、算術式などを指定することができる。

#geshi(bash){{{
# --- commands ---


# Arithmetic expression
(( 0 )); echo $?
(( 1 )); echo $?

#1
ls job.done
if ( cd . && test -f job.done ); then
    echo "job.done found"
fi

#2
i=0
(( i >= 0 )) ; echo $?
if (( i >= 0 )); then
  echo "i is more than 0"
fi

#3
i=0
(( (i >= 0) && (i < 1) )) ; echo $?
!(( (i >= 0) && (i < 1) )) ; echo $?
if !(( (i >= 0) && (i < 1) )); then
  echo "i is not (i >= 0) && (i < 1)"
else
  echo "i is (i >= 0) && (i < 1)"
fi

#4
log="FATAL: unexpected error"
if [[ "$log" =~ ^FATAL ]]; then
  echo "Error detected!"
fi

# --- output ---


# Arithmetic expression
1
0

#1
job.done
job.done found

#2
0
i is more than 0

#3
0
1
i is (i >= 0) && (i < 1)

#4
Error detected!
}}}
*** case [#l507c23a]
#geshi(bash){{{
case word in
    [ [(] pattern [| pattern]…) command-list ;;]…
esac
}}}

- switch case文のようなコマンド。
- ;; で条件区切りとなる。;&、;;& という指定もある。;& は、フォールスルーする。;;& は、次にマッチする条件があるまで辿り、マッチすればcommand-listを実行する。
- patternは、パターンマッチングのルールによって処理される。
- | で区切れば、ORでpatternを複数書くことができる。
- どのpatternにもマッチしない場合は、終了ステータス0となり、マッチすれば、command-listの終了ステータスとなる。

#geshi(bash){{{
# --- commands ---

do_case() {
  echo "cond: $cond"
  case "$cond" in
    start)
      echo "match start"
      ;;
    s*p)
      echo "match s*p"
      ;;
    {a,b,c})
      echo "match {a,b,c}"
      ;;
    [0-5]*|[6-9]+)
      echo "match [0-5]*|[6-9]+"
      ;;
    (~)
      echo "match ~"
      ;&
    (fallback)
      echo "match fallback"
      ;;
    ($USER)
      echo "match \$USER"
      ;;&
    (/$USER)
      echo "match /\$USER"
      ;;
    ($USER*)
      echo "match \$USER*"
      ;;
    *) # default
      echo "cond does not match anything"
      ;;
  esac
}

do_case2() {
  case $cond in
    not) test "1" = "0" ;;
  esac
  echo "status: $?"
}

#1
cond="start"     do_case
#2
cond="stop"      do_case
#3
cond="a b c"     do_case
cond={a,b,c}     do_case
#4
cond="123"       do_case
cond="678"       do_case
#5
cond="unknown"   do_case
#6
cond="$HOME"     do_case
#7
cond="$USER"     do_case

#8
cond="not"       do_case2
cond="notmatch"  do_case2

# --- output ---


#1
cond: start
match start

#2
cond: stop
match s*p

#3
cond: a b c
cond does not match anything
cond: {a,b,c}
match {a,b,c}

#4
cond: 123
match [0-5]*|[6-9]+
cond: 678
cond does not match anything

#5
cond: unknown
cond does not match anything

#6
cond: /home/guest
match ~
match fallback

#7
cond: guest
match $USER
match $USER*

#8
status: 1
status: 0
}}}
*** select [#x4e2affc]

- メニューを生成するコマンド。複数のリストから選択させたい場合に便利である。
- 

#geshi(bash){{{
select name [in words …]; do commands; done
}}}

選択肢を選んだ場合、itemに値が入る。REPLYには、readした値が入る。

#geshi(bash){{{
select item in dog apple orange;
do
  echo you picked $item \($REPLY\)
  break;
done

# ----- output -----

1) dog
2) apple
3) orange
#? 1
you picked dog (1)
}}}

選択肢にない番号を選んだ場合は、nullがセットされる

#geshi(bash){{{
select item in dog apple orange;
do
  echo you picked $item \($REPLY\)
  break
done

# ----- output -----

1) dog
2) apple
3) orange
#? 4
you picked (4)
}}}

何も入力しなかった場合は、再び選択を求められる

#geshi(bash){{{
select item in dog apple orange;
do
  echo you picked $item \($REPLY\)
  break
done

# ----- output -----

1) dog
2) apple
3) orange
#? 
1) dog
2) apple
3) orange
#? 
}}}

変数PS3に値を設定すると、選択時のメッセージをカスタマイズすることができる。

#geshi(bash){{{
PS3="Please select a package you will install: "
menus=(package1 package2 package3)
select item in ${menus[@]};
do
  test -z "$item" && {
    echo "invalid package, please select again"
    continue
  }
  echo "ok, install $item ($REPLY)"
  break
done

# ----- output -----

1) package1
2) package2
3) package3
Please select a package you will install: hoge
invalid package, please select again
Please select a package you will install: 1
ok, install package1 (1)
}}}
*** ((expression)) [#v3a6495d]

 (( expression ))  
 let "expression"

expressionの結果がゼロでない場合、0が返る。そうでない場合は、1。&code(){true};、&code(){false}; を指定しても結果は非ゼロである。

以下一通りの算術演算の結果である。

#geshi(bash){{{
i=0; (( ++i ))      ; echo $?        #=> 0

i=1; (( --i ))      ; echo $?        #=> 1

echo $(( 0 ))                        #=> 0
(( 0 ))       ; echo $?              #=> 1

echo $(( 1 ))                        #=> 1
(( 1 ))       ; echo $?              #=> 0

echo $(( 1 - 1 ))                    #=> 0
(( 1 - 1 ))   ; echo $?              #=> 1

echo $(( 0 + 1 ))                    #=> 1
(( 0 + 1 ))   ; echo $?              #=> 0

echo $(( 1**2 ))                     #=> 1
(( 1**2 ))    ; echo $?              #=> 0

echo $(( 1 * 0 ))                    #=> 0
(( 1 * 0 ))   ; echo $?              #=> 1

echo $(( 0 / 1 ))                    #=> 0
(( 0 / 1 ))   ; echo $?              #=> 1

echo $(( 3 % 3 ))                    #=> 0
(( 3 % 3 ))   ; echo $?              #=> 1

echo $(( 3 % 1 ))                    #=> 0
(( 3 % 1 ))   ; echo $?              #=> 1

echo $(( 2 >> 1 ))                   #=> 1
(( 2 >> 1 ))  ; echo $?              #=> 0

echo $(( 1 << 1 ))                   #=> 2
(( 1 << 1 ))  ; echo $?              #=> 0

echo $(( 1 >= 0 ))                   #=> 1
(( 1 >= 0 ))  ; echo $?              #=> 0

echo $(( 0 <= 0 ))                   #=> 1
(( 0 <= 0 ))  ; echo $?              #=> 0

echo $(( 1 > 0 ))                    #=> 1
(( 1 > 0 ))   ; echo $?              #=> 0

echo $(( 0 < 1 ))                    #=> 1
(( 0 < 1 ))   ; echo $?              #=> 0

echo $(( 1 == 1 ))                   #=> 1
(( 1 == 1 ))  ; echo $?              #=> 0

echo $(( 1 != 0 ))                   #=> 1
(( 1 != 0 ))  ; echo $?              #=> 0

echo $(( 1 & 3 ))                    #=> 1
(( 1 & 3 ))   ; echo $?              #=> 0

echo $(( 1 & 0 ))                    #=> 0
(( 1 & 0 ))   ; echo $?              #=> 1

echo $(( 1 ^ 0 ))                    #=> 1
(( 1 ^ 0 ))   ; echo $?              #=> 0

echo $(( 1 ^ 1 ))                    #=> 0
(( 1 ^ 1 ))   ; echo $?              #=> 1

echo $(( 0 | 1 ))                    #=> 1
(( 0 | 1 ))   ; echo $?              #=> 0

echo $(( 1 | 1 ))                    #=> 1
(( 1 | 1 ))   ; echo $?              #=> 0

echo $(( 1 >= 0 && 1 <= 2 ))         #=> 1
(( 1 >= 0 && 1 <= 2 ))   ; echo $?   #=> 0

echo $(( 0 >= 1 || 1 <= 2 ))         #=> 1
(( 0 >= 1 || 1 <= 2 ))   ; echo $?   #=> 0

echo $(( 1 ? 0 : 1 ))                #=> 0
(( 1 ? 0 : 1 ))   ; echo $?          #=> 1

echo $(( 1, 0 ))                     #=> 0
(( 1, 0 ))   ; echo $?               #=> 1

echo $(( 1, 1 ))                     #=> 1
(( 1, 1 ))   ; echo $?               #=> 0

echo $(( true ))                     #=> 0
(( true ))  ; echo $?                #=> 1

echo $(( false ))                    #=> 0
(( false ))  ; echo $?               #=> 1
}}}

*** [[ expression ]] [#j04884c5]

#geshi(bash){{{
[[ expression ]]
}}}

- [[ は組み込みコマンドである。[ と振る舞いが異なることに注意。
- [[ と ]]; の間のexpressionでは展開の扱いが異なる。
-- 単語分割、ファイル名展開は行われない。
-- チルダ展開、パラメータ・変数展開、算出式展開、コマンド置換、プロセス置換、クオート除去は作用する。
- >、< は、現在のlocaleで作用する。
- ==、!= は、右辺がパターンマーチングのルールで判定される。&code(){extglob}; オプションが有効な場合、= は、 == と等しい。&code(){nocasematch}; オプションが有効な場合、アルファベットの文字大小を無視する。終了ステータスは、== でマッチ、!= でマッチしないを満たす場合は0、そう出ない場合は1。
- =~ は、右辺の文字列をPOSIX拡張正規表現として動作する。正規表現構文が正しくない場合、終了ステータスは2となる。グルーピングにマッチした文字列は、&code(){BASH_REMATCH};配列に保存される。

#geshi(bash){{{
# --- commands ---

touch file_ab
line="ls file_*"
#1
[[ $($line) =~ (.+)_(a)b ]]
echo $?
echo "${BASH_REMATCH[@]}"
#2
[[ "$line" =~ (.+)_(a)b ]]
echo $?
echo "${BASH_REMATCH[@]}"
#3
[[ $(cat <(ls file_*) ) =~ (.+)_(a)b ]]
echo $?
echo "${BASH_REMATCH[@]}"
#4
echo ~
[[ ~ =~ /home/([^/]+) ]]
echo $?
echo "${BASH_REMATCH[@]}"
#5
pattern='/home/([^/]+)'
[[ ~ =~ $pattern ]]
echo $?
echo "${BASH_REMATCH[@]}"
#6 - ""すると、#5とは異なるので注意
pattern='/home/([^/]+)'
[[ ~ =~ "$pattern" ]]
echo $?
echo "${BASH_REMATCH[@]}"
:
[[ '/home/([^/]+)' =~ "$pattern" ]]
echo $?
echo "${BASH_REMATCH[@]}"
#7
pattern='\.'

[[ . =~ $pattern ]]
[[ . =~ \. ]]
echo $?
echo "${BASH_REMATCH[@]}"

[[ . =~ "$pattern" ]]
[[ . =~ '\.' ]]
echo $?
echo "${BASH_REMATCH[@]}"

[[ "\." =~ '\.' ]]
echo $?
echo "${BASH_REMATCH[@]}"

# --- output ---


#1
0
file_ab file a

#2
1


#3
0
file_ab file a

#4
/home/guest
0
/home/guest guest

#5
0
/home/guest guest

#6 - ""すると、#5とは異なるので注意
1

0
/home/([^/]+)

#7
0
.
1

0
\.
}}}
*** ( expression ) [#x75a8176]



***  ! expression [#he71520c]



*** expression1 && expression2、expression1 || expression2 [#dc7f9333]


&label(warn){参考}; https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructs
** [#d0e8fd7a]

* 展開 [#vdd07017]

展開の種類には以下がある。展開の順序を知っておくことで、最終的にどのような結果が得られるのか迷わずに済むだろう。~
以下の順序で展開が行われる。(ただし、二重引用符や単一引用符で囲まれる場合は、いくつかの展開がスキップされたりするがここでは割愛する)

+ ブレース展開
 {a,b}  {x..y..incr}
+ チルダ展開 、[ プロセス置換 ]
 ~  ~-  ~+   [<(list)  or  >(list)]
+ パラメータと変数展開
 ${param} etc
+ コマンド置換
 $(( expression ))
+ 算術式展開
 $(command) or  `command`
+  単語の分割
 word word     split by $IFS
+ パス名展開
 .  *  ?  etc

全ての展開後に、クオートの除去( \   '  "  )が行われる。コマンド検索が行われ、コマンド実行という流れとなる。

&label(warn){参考}; https://www.gnu.org/software/bash/manual/bash.html#Shell-Expansions

** ブレース展開 [#fc2c5271]
 {x..y[..incr]}
 
- {} を使って行なう。ブレース展開を使うと、値の組み合わせのパターン生成に便利な手法。
- 他の展開よりも先に行われるので、変数展開を期待して埋め込んでも意図した結果にならないだろう。
- { や , はバックスラッシュでエスケープできる。

#geshi(bash){{{
param=10                        #=> 

echo `seq 1 10`                 #=> 1 2 3 4 5 6 7 8 9 10
echo {1..10..1}                 #=> 1 2 3 4 5 6 7 8 9 10
echo {1..10..3}                 #=> 1 4 7 10
echo {1..10}                    #=> 1 2 3 4 5 6 7 8 9 10
echo {10..1..-1}                #=> 10 9 8 7 6 5 4 3 2 1
echo {10..-1}                   #=> 10 9 8 7 6 5 4 3 2 1 0 -1
echo {10..10..-1}               #=> 10
echo {1..$param}                #=> {1..10}
eval echo {1..$param}           #=> 1 2 3 4 5 6 7 8 9 10

echo test{1,}                   #=> test1 test
echo test{1,2,3}                #=> test1 test2 test3
echo test{,}                    #=> test test
echo test{{,}}                  #=> test{} test{}
echo {postgresql,pg_hba}.conf   #=> postgresql.conf pg_hba.conf
}}}

&label(warn){参考}; https://www.gnu.org/software/bash/manual/bash.html#Brace-Expansion

** チルダ展開 [#r8b69aa5]

~ や ~-、~+ といった文字列の展開である。

|&code(){~}; |$HOME|
|&code(){~<user>};|ユーザ<user>の$HOME|
|&code(){~+};|$PWD|
|&code(){~-};|${OLDPWD:'~-'}|
|&code(){~N、~+N};|dirs +N|
|&code(){~-N};|dirs -N|

実際の動きを以下例で確認してみる。

#geshi(bash){{{
pwd                             #=> /home/guest/workspace/bash

echo $PWD                       #=> /home/guest/workspace/bash
echo $OLDPWD                    #=> /home/guest/workspace

# ~, ~user
echo ~                          #=> /home/guest
echo ~guest                     #=> /home/guest
echo ~unknownuser               #=> ~unknownuser

# dirs
echo ~+                         #=> /home/guest/workspace/bash
echo ~-                         #=> /home/guest/workspace
unset OLDPWD                    #=> 
echo ~-                         #=> ~-

dirs -l                         #=> /home/guest/workspace/bash

pushd /tmp                      #=> /tmp ~/workspace/bash

echo ~1                         #=> /home/guest/workspace/bash
echo ~+1                        #=> /home/guest/workspace/bash
echo ~-1                        #=> /tmp
}}}


&label(warn){参考}; https://www.gnu.org/software/bash/manual/bash.html#Tilde-Expansion
** パラメータ展開 [#mf070ac4]

*** ${parameter} [#lc33dd13]
parameterの値に置換される。

#geshi(bash){{{
#!/usr/bin/env bash
PARAM="parameter"
echo $PARAM  #=> parameter
}}}

*** ${parameter:-word} [#r6cf08cd]

parameter が設定されていないか空文字列であれば、 wordを展開したものに置換される。そうでなければ、 parameter の値に置換される。

変数のデフォルト値を設定したい場合などによく使う。

#geshi(bash){{{
echo $USER #=> "moritetu"

# ${parameter:-word}
SSH_USER="${USER:-"guest"}"                                                                                                                                          
echo "$SSH_USER" #=> "moritetu"

SSH_OPTS="${OPTIONS:-""}"                                                                                                                                            
echo "$SSH_OPTS"  #=> ""
}}}

*** ${parameter:=word} [#h57e3e86]

parameterが設定されていないか空文字列であれば、 wordを展開したものがparameter に代入される。その後、parameter の値への置換が行われる。

#geshi(bash){{{
# ${parameter:=word}

# ex1
${COMMAND:="date"} #=> 2019年 1月30日 水曜日 22時10分22秒 JST

# ex2
: ${PARAM:="param1"}
echo $PARAM #=> param1
}}}

*** ${parameter:?word} [#v638fa90]

- parameterが空文字列または設定されていない場合、word を展開したものが標準エラー出力に出力される。
- wordがなければ パラメータが空文字列または設定されていないことを示すメッセージが標準エラー出力に出力される。
- 対話的シェルでなければ、 シェルは終了する。
- parameterに空文字列以外が設定されていれば、 parameter 値への置換が行われる。

#geshi(bash){{{
# ${parameter:?word}

# ex1
${not_defined_param:?} #=> not_defined_param: パラメータが null または設定されていません
# シェルは終了する

# ex2
${not_defined_param2:?"parameter is not defined"} #=> not_defined_param2: parameter is not defined
# シェルは終了する

# ex3
defined_param2="defined_param2"
echo ${defined_param2:?"parameter is not defined"} #=> defined_param2
}}}


*** ${parameter:+word} [#g28240aa]

parameter が空文字列または設定されていなければ、空文字列に置換される。そうでなければ word を展開したものに置換される。${parameter:-word} の逆。

#geshi(bash){{{
# ${parameter:+word}

echo ${parameter:+"word"} #=> ""

parameter="defined"
echo ${parameter:+"word"} #=> word
}}}
*** ${parameter:offset}、${parameter:offset:length} [#v6387b01]

- 部分文字列の展開を行なう。
- length指定がある場合は、parameter を展開したものから最大 length 文字を取り出す。length指定がない場合は、指定したインデックスから末尾までの文字を取り出す。
- 配列の場合は、指定したインデックスからlengthで指定される要素を取り出す。

#geshi(bash){{{
# ${parameter:offset}
parameter="012345"              #=> 
array=(0 1 2 3 4 5)             #=> 

echo ${parameter:2}             #=> 2345
echo ${parameter:-1}            #=> 012345
echo ${parameter:-2}            #=> 012345
echo ${array[@]:-2}             #=> 0 1 2 3 4 5
echo ${array[@]:2}              #=> 2 3 4 5
echo ${parameter:2:2}           #=> 23
echo ${parameter:2:-1}          #=> 234
echo ${array[@]:2:1}            #=> 2
echo ${array[@]:2:-1}           #=> parameter.sh: 行 8: -1: substring expression < 0
}}}

*** ${!prefix*}、${!prefix@} [#jd3445b4]

prefix で始まる全ての変数の名前に展開して、 IFS 特殊変数の最初の文字によって区切る。

#geshi(bash){{{
# ${!prefix*}
parameter_1="p1"                #=> 
parameter_2="p2"                #=> 
echo ${!param*}                 #=> parameter_1 parameter_2

(IFS="_|" ; echo ${!param*})    #=> parameter 1 parameter 2

# ${!prefix@}
parameter_1="p1"                #=> 
parameter_2="p2"                #=> 
echo ${!param@}                 #=> parameter_1 parameter_2

for p in "${!param@}"; do eval echo \$$p; done  #=> p1
p2
}}}

*** ${!name[*]}、${!name[@]} [#vf3ba1d3]

- 配列のキーのリストに展開される。ハッシュの場合は、キーを取り出すことができる。
- 配列の場合は、インデックスとなる。*と@の違いは、ダブルクォートで囲まれた場合の展開方法が異なる。

#geshi(bash){{{
array=(a b c d e f)             #=> 
# ${!name[*]}
echo ${!array[*]}               #=> 0 1 2 3 4 5

# ${!name[@]}
echo ${!array[@]}               #=> 0 1 2 3 4 5

# ハッシュ定義
declare -g -A map               #=> 
map=(["a"]=0 ["b"]=1 ["c"]=2 ["d"]=3 ["e"]=4 ["f"]=5)  #=> 
echo ${!map[*]}                 #=> a b c d e f
echo ${map[@]}                  #=> 0 1 2 3 4 5
echo ${!map[@]}                 #=> a b c d e f
}}}
*** ${#parameter} [#h4f5448b]

パラメータの長さを示す。文字列の場合は文字列の長さ、配列の場合は要素数。

#geshi(bash){{{
# ${$parameter}
strings="12345"                 #=> 
echo ${#strings}                #=> 5
strings="あいう"                 #=> 
echo ${#strings}                #=> 3

array=(0 1 2 3 4 5)             #=> 
echo ${#array}                  #=> 1
echo ${#array[@]}               #=> 6
}}}

*** ${parameter#word}、${parameter##word} [#y841fdc6]

- parameterに対しwordで前方一致するパターンを取り除いた結果を返す。#は最短一致、##は最長一致のパターン。
- parameterが@や*の配列変数の場合、全ての要素に対して順番に適用される。


#geshi(bash){{{
parameter="test.sh.j2"          #=> 
array=(index.html.erb hello.html.erb)  #=> 

# ${parameter#word}
echo ${parameter#*.}            #=> sh.j2
echo ${array[@]#*.}             #=> html.erb html.erb

# ${parameter##word}
echo ${parameter##*.}           #=> j2
echo ${array[@]##*.}            #=> erb erb
}}}

*** ${parameter%word}、${parameter%%word} [#tf4bc178]

- parameterに対しwordで''後方一致''するパターンを取り除いた結果を返す。#は最短一致、##は最長一致のパターン。
- parameterが@や*の配列変数の場合、全ての要素に対して順番に適用される。


#geshi(bash){{{
parameter="test.sh.j2"          #=> 
array=(index.html.erb hello.html.erb)  #=> 

# ${parameter%word}
echo ${parameter%.*}            #=> test.sh
echo ${array[@]%.*}             #=> index.html hello.html

# ${parameter%%word}
echo ${parameter%%.*}           #=> test
echo ${array[@]%%.*}            #=> index hello
}}}

*** ${parameter/pattern/string} [#i4603bba]

- parameterのpatternの最長一致する部分をstringに置換する。
- / で始まる場合は、patternにマッチした全てが置換される。
- # で始まる場合は、parameterを展開した値の先頭にマッチ。
- %で始まる場合は、parameterを展開した値の末尾にマッチ。
- parameterが、@や*の場合は、全ての要素に適用される。

#geshi(bash){{{
parameter="# this is a comment line."  #=> 
array=("# this is a comment line." "# this is not a comment line.")  #=> 

# ${parameter/pattern/string}
echo ${parameter/i/I}           #=> # thIs is a comment line.
echo ${parameter//i/I}          #=> # thIs Is a comment lIne.
echo ${parameter[*]//i/I}       #=> # thIs Is a comment lIne.

echo ${parameter/##/#=>}        #=> #=> this is a comment line.
echo ${parameter/#this/This}    #=> # this is a comment line.
echo ${parameter[@]/#this/This}  #=> # this is a comment line.

echo ${parameter/%./!}          #=> # this is a comment line!
echo ${parameter/%e/!}          #=> # this is a comment line.
echo ${parameter[@]/%e/!}       #=> # this is a comment line.
}}}

*** ${parameter^pattern}、${parameter^^pattern}、${parameter,pattern}、${parameter,,pattern} [#lce334bc]

- parameterに含まれるアルファベットの大文字小文字を変換する。
- ^ は、patternにマッチした小文字を大文字に変換し、, は、大文字を小文字に変換する。これらは、最初にマッチした部分のみ置換する。
- ^^ と ,, は、マッチした全ての文字を置換する。
- parameterが、@や* の場合は、全ての要素に適用される。

#geshi(bash){{{
parameter="hellO, WOrld"        #=> 
array=("hellO, WOrld" "hellO, WOrld2")  #=> 

# ${parameter^pattern}
echo ${parameter^l}             #=> hellO, WOrld
echo ${array[@]^l}              #=> hellO, WOrld hellO, WOrld2

# ${parameter^^pattern}
echo ${parameter^^l}            #=> heLLO, WOrLd
echo ${array[@]^^l}             #=> heLLO, WOrLd heLLO, WOrLd2

# ${parameter,pattern}
echo ${parameter,O}             #=> hellO, WOrld
echo ${array[@],,O}             #=> hello, World hello, World2

# ${parameter,,pattern}
echo ${parameter,,O}            #=> hello, World
echo ${array[@],,O}             #=> hello, World hello, World2
}}}


&label(warn){参考}; https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion
* プロセス置換 [#we760055]

- &code(){>(list)};は、ファイルへの出力がlistへの入力となる。
- &code(){<(list)};は、listの出力がファイルへの入力となる。

&label(sample){サンプル}; ''lsの結果で*.shファイルのみを出力''

#geshi(bash,number){{{
a=
while IFS= read -r line
do
  a="$line:$a"
done < <(ls . | grep -e "\.sh$")
}}}

&label(sample){サンプル}; ''a.txtとb.txtをdiffの入力ファイルとして比較''

#geshi(bash,number){{{
diff -u <(cat a.txt) <(cat b.txt)
}}}

&label(sample){サンプル}; 

#geshi(bash,number){{{
exec 3>&1
exec > >(while read line; do echo "$(date): $line";done)

echo "hello"
echo "bar"

exec 1>&3 3>&-
}}}
* execを使った入出力のリダイレクト [#s12f0ef4]

execコマンドでリダイレクトだけを指定すると、シェル自身のファイル記述子とデバイスの対応を変更することができる。

****  &label(sample){例}; execを使った入力のリダイレクト [#z15e5164]
#geshi(bash,number){{{
# copy stdin to descriptor 3
exec 3<&0

# redirect stdin to test.c
exec < test.c

# read a line from test.c
read line
echo $line

# restore stdin and close descriptor 3
exec 0<&3 3<&-
}}}

**** &label(sample){例}; execを使った出力のリダイレクト [#z15e5164]

#geshi(bash,number){{{
# save stdout as descriptor 3
exec 3>&1

exec > test.txt

echo "this message is written into the test.txt"

# restore stdout and close descriptor 3
exec 1>&3 3>&-
}}}

特定の式や文の出力をまとめてリダイレクトしたい場合は、ブレースを使った複合コマンドでも処理できる。

&label(sample){例}; ''複合コマンドの出力をファイルにリダイレクトする''

#geshi(bash,number){{{
#!/usr/bin/env bash

# 複合コマンド
{
  # stdout.txtに出力
  echo "this message is written into stdout.txt"
  # stderr.txtに出力
  echo "this message is written into stderr.txt" >&2
} > stdout.txt 2> stderr.txt
}}}
* 参考リンク [#q8d32fb3]
- [[(PR) 入門bash 第3版>http://www.amazon.co.jp/exec/obidos/ASIN/4873112540/grepgrape-22/ref=nosim/]] - &size(11){&color(gray){on http://www.amazon.co.jp/exec/obidos/ASIN/4873112540/};};

- [[Advanced Bash-Scripting Guid>http://tldp.org/LDP/abs/html/index.html]] - &size(11){&color(gray){on http://tldp.org/LDP/abs/html/index.html};};
- [[GNU Bash manual>https://www.gnu.org/software/bash/manual/]] - &size(11){&color(gray){on https://www.gnu.org/software/bash/manual/};};
- [[Man page of BASH>https://linuxjm.osdn.jp/html/GNU_bash/man1/bash.1.html]] - &size(11){&color(gray){on https://linuxjm.osdn.jp/html/GNU_bash/man1/bash.1.html};};
- テストフレームワーク
-- [[Bats>https://github.com/sstephenson/bats]] - &size(11){&color(gray){on https://github.com/sstephenson/bats};};
-- [[shunit2>https://github.com/kward/shunit2]] - &size(11){&color(gray){on https://github.com/kward/shunit2};};
--- [[Pac Learner shUnit2 2.1.x ドキュメント>https://sites.google.com/site/paclearner/shunit2-documentation]] - &size(11){&color(gray){on https://sites.google.com/site/paclearner/shunit2-documentation};};
-- [[Baut (Bash Unittest Tool)>https://github.com/moritetu/baut]] - - &size(11){&color(gray){on https://github.com/moritetu/baut};};

- [[Bash $((算術式)) のすべて - A 基本編>https://qiita.com/akinomyoga/items/9761031c551d43307374]] - &size(11){&color(gray){on https://qiita.com/akinomyoga/items/9761031c551d43307374};};

トップ   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
目次
ダブルクリックで閉じるTOP | 閉じる
GO TO TOP