- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- ソース を表示
- Bash へ行く。
- 1 (2018-03-18 (日) 20:49:33)
- 2 (2018-03-20 (火) 09:06:21)
- 3 (2019-01-06 (日) 09:24:42)
- 4 (2019-01-12 (土) 21:48:28)
- 5 (2019-01-31 (木) 07:20:51)
- 6 (2019-02-01 (金) 09:43:35)
- 7 (2019-02-02 (土) 09:46:16)
- 8 (2019-02-03 (日) 02:20:06)
- 9 (2019-02-03 (日) 05:36:51)
- 10 (2019-02-04 (月) 05:00:39)
- 11 (2019-02-07 (木) 08:53:49)
- 12 (2019-02-10 (日) 00:28:39)
- 13 (2019-02-10 (日) 03:20:26)
- 14 (2019-02-10 (日) 08:34:09)
- 15 (2019-02-25 (月) 04:44:27)
- 16 (2019-02-25 (月) 08:11:51)
- 17 (2019-02-26 (火) 08:06:29)
- 18 (2019-02-27 (水) 10:02:53)
- 19 (2019-02-28 (木) 09:38:29)
- 20 (2019-03-05 (火) 09:54:13)
- 21 (2019-03-06 (水) 09:17:25)
- 22 (2019-03-07 (木) 07:41:27)
- 23 (2019-03-09 (土) 09:17:38)
- 24 (2019-03-09 (土) 23:41:50)
- 25 (2019-03-10 (日) 07:31:44)
- 26 (2019-03-10 (日) 10:33:46)
- 27 (2019-03-10 (日) 19:16:58)
- 28 (2019-03-17 (日) 07:32:30)
- 29 (2019-03-17 (日) 19:35:17)
- 30 (2019-03-18 (月) 01:12:00)
- 31 (2019-03-22 (金) 07:12:56)
- 32 (2019-03-23 (土) 22:12:31)
- 33 (2019-03-24 (日) 09:14:12)
- 34 (2019-03-26 (火) 08:55:27)
- 35 (2019-03-27 (水) 09:31:09)
- 36 (2019-03-28 (木) 06:30:44)
- 37 (2019-03-29 (金) 09:01:02)
- 38 (2019-03-30 (土) 09:06:01)
- 39 (2019-03-30 (土) 20:22:20)
- 40 (2019-04-01 (月) 08:03:58)
- 41 (2019-04-04 (木) 08:48:41)
- 42 (2019-04-06 (土) 21:07:53)
- 43 (2019-04-11 (木) 06:27:12)
- 44 (2019-05-01 (水) 22:54:09)
- 45 (2019-05-02 (木) 07:50:54)
- 46 (2019-05-02 (木) 19:19:20)
- 47 (2019-05-04 (土) 06:04:16)
- 48 (2019-05-04 (土) 07:35:38)
- 49 (2019-05-06 (月) 07:23:05)
- 50 (2019-07-25 (木) 07:54:44)
- 51 (2020-01-31 (金) 21:32:23)
Bashマニュアルから(自分が)頻繁に使用するであろう機能をピックアップしてまとめる。
- コマンド
- 展開
- ブレース展開
- チルダ展開
- パラメータ展開
- ${parameter}
- ${parameter:-word}
- ${parameter:=word}
- ${parameter:?word}
- ${parameter:+word}
- ${parameter:offset}、${parameter:offset:length}
- ${!prefix*}、${!prefix@}
- ${!name[*]}、${!name[@]}
- ${#parameter}
- ${parameter#word}、${parameter##word}
- ${parameter%word}、${parameter%%word}
- ${parameter/pattern/string}
- ${parameter^pattern}、${parameter^^pattern}、${parameter,pattern}、${parameter,,pattern}
- プロセス置換
- execを使った入出力のリダイレクト
- 参考リンク
コマンド †
ループ †
until †
until test-commands; do consequent-commands; done
条件が成り立つまで繰り返す。
# --- 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 †
while test-commands; do consequent-commands; done
条件が成り立つ間繰り返す。
# --- 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 †
for name [ [in [words …] ] ; ] do commands; done for (( expr1 ; expr2 ; expr3 )) ; do commands ; done
wordsの数繰り返す。*1
は、他のプログラミング言語同様の構文。
expr1が最初に評価され、expr2がゼロになるまで、commandsを繰り返し評価する。expr2がゼロでない場合は、expr3が評価される。
# --- 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
参考 https://www.gnu.org/software/bash/manual/bash.html#Looping-Constructs
条件 †
if †
if test-commands; then consequent-commands; [elif more-test-commands; then more-consequents;] [else alternate-consequents;] fi
ifの条件式には、コマンドやBashの条件式(-aや-fなど)、算術式などを指定することができる。
# --- 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 †
case word in [ [(] pattern [| pattern]…) command-list ;;]… esac
- switch case文のようなコマンド。
- ;; で条件区切りとなる。;&、;;& という指定もある。;& は、フォールスルーする。;;& は、次にマッチする条件があるまで辿り、マッチすればcommand-listを実行する。
- patternは、パターンマッチングのルールによって処理される。
- | で区切れば、ORでpatternを複数書くことができる。
- どのpatternにもマッチしない場合は、終了ステータス0となり、マッチすれば、command-listの終了ステータスとなる。
# --- 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 †
- メニューを生成するコマンド。複数のリストから選択させたい場合に便利である。
select name [in words …]; do commands; done
選択肢を選んだ場合、itemに値が入る。REPLYには、readした値が入る。
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がセットされる
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)
何も入力しなかった場合は、再び選択を求められる
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に値を設定すると、選択時のメッセージをカスタマイズすることができる。
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)) †
(( expression )) let "expression"
expressionの結果がゼロでない場合、0が返る。そうでない場合は、1。true
、false
を指定しても結果は非ゼロである。
以下一通りの算術演算の結果である。
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 ]] †
[[ expression ]]
- [[ は組み込みコマンドである。[ と振る舞いが異なることに注意。
- [[ と ]]; の間のexpressionでは展開の扱いが異なる。
- 単語分割、ファイル名展開は行われない。
- チルダ展開、パラメータ・変数展開、算出式展開、コマンド置換、プロセス置換、クオート除去は作用する。
- >、< は、現在のlocaleで作用する。
- ==、!= は、右辺がパターンマーチングのルールで判定される。
extglob
オプションが有効な場合、= は、 == と等しい。nocasematch
オプションが有効な場合、アルファベットの文字大小を無視する。終了ステータスは、== でマッチ、!= でマッチしないを満たす場合は0、そう出ない場合は1。 - =~ は、右辺の文字列をPOSIX拡張正規表現として動作する。正規表現構文が正しくない場合、終了ステータスは2となる。グルーピングにマッチした文字列は、
BASH_REMATCH
配列に保存される。
# --- 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 ) †
expressionの値を返す。演算子の優先順位を変えたい時とか。
# --- commands --- i=-1 #1 if (( i > 0 && i < 100 || i < 0 )); then echo "#1 true" else echo "#1 false" fi #2 if (( i > 0 && ( i < 100 || i < 0 ) )); then echo "#2 true" else echo "#2 false" fi # --- output --- #1 #1 true #2 #2 false
! expression †
expressionがtrueならばfalseを返す。
# --- commands --- #1 if (( 1 > 0 )); then echo "true" else echo "false" fi #2 if (( !(1 > 0) )); then echo "true" else echo "false" fi # --- output --- #1 true #2 false
expression1 && expression2、expression1 || expression2 †
expression1で全体の真、偽が決まる場合は、expression2を評価しない。
- expression1 && expression2
- expression1がfalse、expression2は評価しない、結果はfalse
- expression1 || expression2
- expression1がtrue、expression2は評価しない、結果はtrue
(( 1 > 0 )) && { echo "expr2"; } #=> expr2 (( 1 < 0 )) && { echo "expr2"; } #=> (( 1 > 0 )) || { echo "expr2"; } #=> (( 1 < 0 )) || { echo "expr2"; } #=> expr2
参考 https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructs
グルーピング †
( list ) †
サブシェルで実行される。変数の割り当ても親シェルには影響しない。
親シェルのPWDはそのままで、一時的にcdして何らかの処理を実行するといった時にも使える。
# --- commands --- PARAM=10 ( PARAM=20 ; echo $PARAM ) echo $PARAM mkdir -p subdir pwd ( cd subdir; pwd; ) pwd # --- output --- 20 10 /home/guest/workspace/bash /home/guest/workspace/bash/subdir /home/guest/workspace/bash
{ list; } †
現在のコンテキストで実行される。}の後にリダイレクトを指定すると、グルーピングされたコマンドの結果をリダイレクト先にまとめて送ることができる。
# --- commands --- PARAM=10 { PARAM=20 ; echo $PARAM ; } echo $PARAM { echo "foo" echo "bar" } > out.txt cat out.txt mkdir -p subdir pwd { cd subdir; pwd; } pwd # --- output --- 20 20 foo bar /home/guest/workspace/bash /home/guest/workspace/bash/subdir /home/guest/workspace/bash/subdir
参考 https://www.gnu.org/software/bash/manual/bash.html#Command-Grouping
Coprocesses †
coproc [NAME] command [redirections]
- サブシェルで非同期にコマンド実行することができる。&を使ったバックグラウンド実行と似ている。coprocで実行されたシェルと実行元のシェル間にはstdinとstdoutのパイプが作られる。pipeを呼び、forkしている。
- コマンドのstdoutは NAME[0]、stdinは NAME[1]
# --- commands --- coproc MY { read line echo "$line, guest!" sleep 1 echo "hello" sleep 1 } echo ${MY[@]} echo "hello" >&${MY[1]} cat - <&${MY[0]} wait # --- output --- 63 60 hello, guest! hello
展開 †
展開の種類には以下がある。展開の順序を知っておくことで、最終的にどのような結果が得られるのか迷わずに済むだろう。
以下の順序で展開が行われる。(ただし、二重引用符や単一引用符で囲まれる場合は、いくつかの展開がスキップされたりするがここでは割愛する)
- ブレース展開
{a,b} {x..y..incr}
- チルダ展開 、[ プロセス置換 ]
~ ~- ~+ [<(list) or >(list)]
- パラメータと変数展開
${param} etc
- コマンド置換
$(( expression ))
- 算術式展開
$(command) or `command`
- 単語の分割
word word split by $IFS
- パス名展開
. * ? etc
全ての展開後に、クオートの除去( \ ' " )が行われる。コマンド検索が行われ、コマンド実行という流れとなる。
参考 https://www.gnu.org/software/bash/manual/bash.html#Shell-Expansions
ブレース展開 †
{x..y[..incr]}
- {} を使って行なう。ブレース展開を使うと、値の組み合わせのパターン生成に便利な手法。
- 他の展開よりも先に行われるので、変数展開を期待して埋め込んでも意図した結果にならないだろう。
- { や , はバックスラッシュでエスケープできる。
name () compound-command [ redirections ] function name [()] compound-command [ redirections ]
参考 https://www.gnu.org/software/bash/manual/bash.html#Brace-Expansion
チルダ展開 †
や ~-、~+ といった文字列の展開である。
~ | $HOME |
~<user> | ユーザ<user>の$HOME |
~+ | $PWD |
~- | ${OLDPWD:'~-'} |
~N、~+N | dirs +N |
~-N | dirs -N |
実際の動きを以下例で確認してみる。
# --- commands --- :> "$PWD/output" hello() { echo "hello func" } # functionがある場合は()は省略可 function hello_with_redirections { echo "$@" } &>> "$PWD/output" shortfunc() { echo "$FUNCNAME"; } shortfunc2() { echo "this is ok"; } # shortfunc3() { echo "this is error, ; is required" } #1 hello #2 hello_with_redirections "hello redirections" #3 cat "$PWD/output" #4 shortfunc #5 shortfunc2 # shortfunc3 # --- output --- #1 hello func #2 #3 hello redirections #4 shortfunc #5 this is ok
参考 https://www.gnu.org/software/bash/manual/bash.html#Tilde-Expansion
パラメータ展開 †
${parameter} †
parameterの値に置換される。
# --- commands --- function myfunc() { echo $FUNCNAME } # 関数定義の確認 #1 type myfunc ; echo $? #2 type -t myfunc ; echo $? #3 myfunc # 関数定義を削除 #4 unset -f myfunc ; echo $? #5 type myfunc ; echo $? # --- output --- #1 myfunc は関数です myfunc () { echo $FUNCNAME } 0 #2 function 0 #3 myfunc #4 0 #5 type: myfunc: 見つかりません 1
${parameter:-word} †
parameter が設定されていないか空文字列であれば、 wordを展開したものに置換される。そうでなければ、 parameter の値に置換される。
変数のデフォルト値を設定したい場合などによく使う。
# --- commands --- f0() { echo ${FUNCNAME[@]} } f1() { f0 } f2() { f1 } #1 f2 # --- output --- #1 f0 f1 f2 main
${parameter:=word} †
parameterが設定されていないか空文字列であれば、 wordを展開したものがparameter に代入される。その後、parameter の値への置換が行われる。
# --- commands --- function f0() { var="change to f0" echo "6) After change: In $FUNCNAME, var=$var" } function f1() { echo "1) In $FUNCNAME, var=$var" local var="f1" echo "2) Define local: In $FUNCNAME, var=$var" unset var echo "3) After unset: In $FUNCNAME, var=$var" var="change to f1" echo "4) After change: In $FUNCNAME, var=$var" } function f2() { local var="f2" f1 echo "5) In $FUNCNAME, var=$var" f0 } function f3() { var="change to f3" echo "8) After change: In $FUNCNAME, var=$var" } var="global" f2 echo "7) In $FUNCNAME, var=$var" f3 echo "9) In $FUNCNAME, var=$var" # --- output --- 1) In f1, var=f2 2) Define local: In f1, var=f1 3) After unset: In f1, var= 4) After change: In f1, var=change to f1 5) In f2, var=f2 6) After change: In f0, var=change to f0 7) In , var=global 8) After change: In f3, var=change to f3 9) In , var=change to f3
${parameter:?word} †
- parameterが空文字列または設定されていない場合、word を展開したものが標準エラー出力に出力される。
- wordがなければ パラメータが空文字列または設定されていないことを示すメッセージが標準エラー出力に出力される。
- 対話的シェルでなければ、 シェルは終了する。
- parameterに空文字列以外が設定されていれば、 parameter 値への置換が行われる。
# --- commands --- function my1() { : } function my2() { : } typeset -f typeset -F # --- output --- my1 () { : } my2 () { : } declare -f my1 declare -f my2
${parameter:+word} †
parameter が空文字列または設定されていなければ、空文字列に置換される。そうでなければ word を展開したものに置換される。${parameter:-word} の逆。
name=[value]
${parameter:offset}、${parameter:offset:length} †
- 部分文字列の展開を行なう。
- length指定がある場合は、parameter を展開したものから最大 length 文字を取り出す。length指定がない場合は、指定したインデックスから末尾までの文字を取り出す。
- 配列の場合は、指定したインデックスからlengthで指定される要素を取り出す。
b=1 b+=1 echo $b #=> 11 # integerとして定義 declare -i a a=1 a+=1 echo $a #=> 2 # 配列として定義 declare -a arr arr=(1 2) arr+=(1) echo ${arr[*]} #=> 1 2 1 arr+=1 # この場合は、arr[0]の値に1が追加される echo ${arr[*]} #=> 11 2 1 # 連想配列として定義 declare -A map map=(["a"]=1 ["b"]=2) map+=(["c"]=5) echo ${map[@]} #=> 1 2 5 echo ${!map[@]} #=> a b c map["e"]=6 echo ${!map[@]} #=> a b c e echo ${map[@]} #=> 1 2 5 6
${!prefix*}、${!prefix@} †
prefix で始まる全ての変数の名前に展開して、 IFS 特殊変数の最初の文字によって区切る。
# --- commands --- my() { local -n ref=$1 ref=${ref^^t} } var="test" # 変数名を渡し関数内で操作 my var #1 echo $var declare -n ref2=var declare -n ref3=var #2 -nオプションありでunset declare -p ref2 unset -n ref2 declare -p ref2 #3 -nオプションなしでunset declare -p var declare -p ref3 unset ref3 declare -p ref3 declare -p var # --- output --- #1 TesT #2 -nオプションありでunset declare -n ref2="var" declare -- ref2 #3 -nオプションなしでunset declare -- var="TesT" declare -n ref3="var" declare -n ref3="var" declare: var: 見つかりません
${!name[*]}、${!name[@]} †
- 配列のキーのリストに展開される。ハッシュの場合は、キーを取り出すことができる。
- 配列の場合は、インデックスとなる。*と@の違いは、ダブルクォートで囲まれた場合の展開方法が異なる。
# --- commands --- a="echo a > out" b="echo b >> out" c="echo c >> out" d="cat out" declare -n ref for ref in {a,b,c,d}; do # a b c dの変数に設定されているコマンド文字列を実行 eval $ref done # --- output --- a b c
${#parameter} †
パラメータの長さを示す。文字列の場合は文字列の長さ、配列の場合は要素数。
# --- commands --- # file: vars2.sh arg_n=66001 function f() { echo $0 local v= i # 1000ずつ飛ばして表示してみる for i in $(seq 1 1000 $arg_n); do v="\${$i}" printf "# $v = %s " "$(eval echo $v)" done } function f2() { echo "in f2: len(args) = $#" while [ $# -gt 0 ]; do echo $1 shift done } #1 echo $0 #2 f $(seq 1 $arg_n | xargs printf 'A%d ') #3 set a b c d # 位置パラメータに値を設定 while [ $# -gt 0 ]; do echo $1 shift 2 # 1つ飛ばしで done #4 f2 a b c d #5 echo $- # --- output --- #1 vars2.sh #2 vars2.sh # ${1} = A1 # ${1001} = A1001 # ${2001} = A2001 # ${3001} = A3001 # ${4001} = A4001 # ${5001} = A5001 # ${6001} = A6001 # ${7001} = A7001 # ${8001} = A8001 # ${9001} = A9001 # ${10001} = A10001 # ${11001} = A11001 # ${12001} = A12001 # ${13001} = A13001 # ${14001} = A14001 # ${15001} = A15001 # ${16001} = A16001 # ${17001} = A17001 # ${18001} = A18001 # ${19001} = A19001 # ${20001} = A20001 # ${21001} = A21001 # ${22001} = A22001 # ${23001} = A23001 # ${24001} = A24001 # ${25001} = A25001 # ${26001} = A26001 # ${27001} = A27001 # ${28001} = A28001 # ${29001} = A29001 # ${30001} = A30001 # ${31001} = A31001 # ${32001} = A32001 # ${33001} = A33001 # ${34001} = A34001 # ${35001} = A35001 # ${36001} = A36001 # ${37001} = A37001 # ${38001} = A38001 # ${39001} = A39001 # ${40001} = A40001 # ${41001} = A41001 # ${42001} = A42001 # ${43001} = A43001 # ${44001} = A44001 # ${45001} = A45001 # ${46001} = A46001 # ${47001} = A47001 # ${48001} = A48001 # ${49001} = A49001 # ${50001} = A50001 # ${51001} = A51001 # ${52001} = A52001 # ${53001} = A53001 # ${54001} = A54001 # ${55001} = A55001 # ${56001} = A56001 # ${57001} = A57001 # ${58001} = A58001 # ${59001} = A59001 # ${60001} = A60001 # ${61001} = A61001 # ${62001} = A62001 # ${63001} = A63001 # ${64001} = A64001 # ${65001} = A65001 # ${66001} = A66001 #3 a c #4 in f2: len(args) = 4 a b c d #5 hB
${parameter#word}、${parameter##word} †
- parameterに対しwordで前方一致するパターンを取り除いた結果を返す。#は最短一致、##は最長一致のパターン。
- parameterが@や*の配列変数の場合、全ての要素に対して順番に適用される。
# --- commands --- function f() { echo "$1" echo "$2" echo "$3" echo "in f(): args= $*" # $1 $2 ... f2 $* # "$1" "$2" ... f2 "$*" # "s $1" ... "$4 z" f2 "s $* z" } function f2() { echo "in f2(): args= $*" echo "num: $#" echo "$1" echo "$2" echo "$3" echo "$4" } function f3() { echo "in f3()" # $1 $2 ... $* } function f4() { echo "in f4()" # "$1" "$2" ... "$*" } function f5() { echo "in f5()" # "$10$2" ... ( IFS=0 && echo "$*" ) # "$1$2" ... ( IFS= && echo "$*" ) } f a b c d f3 "echo hello" f4 "echo hello" f5 "echo" "hello" # --- output --- a b c in f(): args= a b c d in f2(): args= a b c d num: 4 a b c d in f2(): args= a b c d num: 1 a b c d in f2(): args= s a b c d z num: 1 s a b c d z in f3() hello in f4() template.sh: 行 71: echo hello: コマンドが見つかりません in f5() echo0hello echohello
${parameter%word}、${parameter%%word} †
- parameterに対しwordで後方一致するパターンを取り除いた結果を返す。#は最短一致、##は最長一致のパターン。
- parameterが@や*の配列変数の場合、全ての要素に対して順番に適用される。
# --- commands --- function f() { echo "$1" echo "$2" echo "$3" echo "in f(): args= $@" # $1 $2 ... f2 $@ # "$1" "$2" ... f2 "$@" # "s $1" ... "$4 z" f2 "s $@ z" } function f2() { echo "in f2(): args= $@" echo "num: $#" echo "$1" echo "$2" echo "$3" echo "$4" } function f3() { # $1 $2 ... $@ } function f4() { # "$1" "$2" ... "$@" } f a b c d f3 "echo hello" f4 "echo hello" # --- output --- a b c in f(): args= a b c d in f2(): args= a b c d num: 4 a b c d in f2(): args= a b c d num: 4 a b c d in f2(): args= s a b c d z num: 4 s a b c d z hello echo hello: コマンドが見つかりません
${parameter/pattern/string} †
- parameterのpatternの最長一致する部分をstringに置換する。
- / で始まる場合は、patternにマッチした全てが置換される。
- # で始まる場合は、parameterを展開した値の先頭にマッチ。
- %で始まる場合は、parameterを展開した値の末尾にマッチ。
- parameterが、@や*の場合は、全ての要素に適用される。
# file: test.sh echo $@ echo $# ar=(1 2 3) echo ${#ar[@]} # --- output --- $ ./test.sh 1 2 3 1 2 3 3 3
${parameter^pattern}、${parameter^^pattern}、${parameter,pattern}、${parameter,,pattern} †
- parameterに含まれるアルファベットの大文字小文字を変換する。
- ^ は、patternにマッチした小文字を大文字に変換し、, は、大文字を小文字に変換する。これらは、最初にマッチした部分のみ置換する。
- ^^ と ,, は、マッチした全ての文字を置換する。
- parameterが、@や* の場合は、全ての要素に適用される。
# --- commands --- function f_ret_0() { [ 1 -ne 1 ] # result should not be 0 } function f2_ret_0() { [ 1 -ne 1 ] echo "f2" # result should be 0 } function f3_ret_0() { case "$1" in -h) echo "option -h" ;; esac # result should be 0 } function f4_ret_not_0() { case "$1" in -h) echo "option -h" [ 1 -ne 1 ] ;; esac # result should not be 0 } #1 (( 1 == 1 )) echo $? #2: function f ends with exit status not 0 f_ret_0 echo $? #3: function f2 ends with exit status 0 f2_ret_0 echo $? #4: function f3 ends with exit status 0 f3_ret_0 -p echo $? #4: function f4 ends with exit status not 0 f4_ret_not_0 -h echo $? # --- output --- #1 0 #2: function f ends with exit status not 0 1 #3: function f2 ends with exit status 0 f2 0 #4: function f3 ends with exit status 0 0 #4: function f4 ends with exit status not 0 option -h 1
参考 https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion
プロセス置換 †
>(list)
は、ファイルへの出力がlistへの入力となる。<(list)
は、listの出力がファイルへの入力となる。
サンプル lsの結果で*.shファイルのみを出力
set -x echo $- set +x echo $- # ----- output ----- + echo hxB hxB + set +x hB
サンプル a.txtとb.txtをdiffの入力ファイルとして比較
$ echo $- himBH
サンプル
echo $BASHPID #=> 42071 echo $$ #=> 42071 bash -c 'echo $BASHPID; echo $$' #=> 42079 42079 ( echo $$ ) #=> 42071
execを使った入出力のリダイレクト †
execコマンドでリダイレクトだけを指定すると、シェル自身のファイル記述子とデバイスの対応を変更することができる。
例 execを使った入力のリダイレクト †
$ sleep 30 & [1] 15816 $ echo $! 15816 $ echo "hello" hello $ echo $! 15816 $ sleep 30 & [2] 15870 $ echo $! 15870 $ jobs -l [1]- 15816 Running sleep 30 & [2]+ 15870 Running sleep 30 &
例 execを使った出力のリダイレクト †
#!/usr/bin/env bash pidfile=job.pids nohup bash -c 'i=0; while ((i<10)); do echo job1-$i; ((i++)); done' > stdout-1 2> stderr-1 & echo $! > job.pids nohup bash -c 'i=0; while ((i<10)); do echo job2-$i; ((i++)); done' > stdout-2 2> stderr-2 & echo $! >> job.pids
使い道はさておき、こんなのもできる。
# hello.sh echo $0 # --------- ./hello.sh #=> ./hello.sh bash hello.sh #=> hello.sh
特定の式や文の出力をまとめてリダイレクトしたい場合は、ブレースを使った複合コマンドでも処理できる。
例 複合コマンドの出力をファイルにリダイレクトする
bash -c 'echo $0' #=> bash bash -c 'echo $0' hello #=> hello