- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- ソース を表示
- 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 †
switch case文のようなコマンド。
case word in [ [(] pattern [| pattern]…) command-list ;;]… esac
select †
メニューを生成するコマンド。複数のリストから選択させたい場合に便利である。
# --- 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
expression †
(( expression )) let "expression"
expressionの結果がゼロでない場合、0が返る。そうでない場合は、1。
[[ expression ]]
( expression )
! expression
expression1 && expression2
expression1 || expression2
参考 https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructs
†
展開 †
展開の種類には以下がある。展開の順序を知っておくことで、最終的にどのような結果が得られるのか迷わずに済むだろう。
以下の順序で展開が行われる。(ただし、二重引用符や単一引用符で囲まれる場合は、いくつかの展開がスキップされたりするがここでは割愛する)
- ブレース展開
{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]}
- {} を使って行なう。ブレース展開を使うと、値の組み合わせのパターン生成に便利な手法。
- 他の展開よりも先に行われるので、変数展開を期待して埋め込んでも意図した結果にならないだろう。
- { や , はバックスラッシュでエスケープできる。
select name [in words …]; do commands; done
参考 https://www.gnu.org/software/bash/manual/bash.html#Brace-Expansion
チルダ展開 †
や ~-、~+ といった文字列の展開である。
~ | $HOME |
~<user> | ユーザ<user>の$HOME |
~+ | $PWD |
~- | ${OLDPWD:'~-'} |
~N、~+N | dirs +N |
~-N | dirs -N |
実際の動きを以下例で確認してみる。
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)
参考 https://www.gnu.org/software/bash/manual/bash.html#Tilde-Expansion
パラメータ展開 †
${parameter} †
parameterの値に置換される。
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)
${parameter:-word} †
parameter が設定されていないか空文字列であれば、 wordを展開したものに置換される。そうでなければ、 parameter の値に置換される。
変数のデフォルト値を設定したい場合などによく使う。
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 #?
${parameter:=word} †
parameterが設定されていないか空文字列であれば、 wordを展開したものがparameter に代入される。その後、parameter の値への置換が行われる。
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)
${parameter:?word} †
- parameterが空文字列または設定されていない場合、word を展開したものが標準エラー出力に出力される。
- wordがなければ パラメータが空文字列または設定されていないことを示すメッセージが標準エラー出力に出力される。
- 対話的シェルでなければ、 シェルは終了する。
- parameterに空文字列以外が設定されていれば、 parameter 値への置換が行われる。
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
${parameter:+word} †
parameter が空文字列または設定されていなければ、空文字列に置換される。そうでなければ word を展開したものに置換される。${parameter:-word} の逆。
[[ expression ]]
${parameter:offset}、${parameter:offset:length} †
- 部分文字列の展開を行なう。
- length指定がある場合は、parameter を展開したものから最大 length 文字を取り出す。length指定がない場合は、指定したインデックスから末尾までの文字を取り出す。
- 配列の場合は、指定したインデックスからlengthで指定される要素を取り出す。
# --- 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 \.
${!prefix*}、${!prefix@} †
prefix で始まる全ての変数の名前に展開して、 IFS 特殊変数の最初の文字によって区切る。
# --- 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
${!name[*]}、${!name[@]} †
- 配列のキーのリストに展開される。ハッシュの場合は、キーを取り出すことができる。
- 配列の場合は、インデックスとなる。*と@の違いは、ダブルクォートで囲まれた場合の展開方法が異なる。
# --- 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
${#parameter} †
パラメータの長さを示す。文字列の場合は文字列の長さ、配列の場合は要素数。
(( 1 > 0 )) && { echo "expr2"; } #=> expr2 (( 1 < 0 )) && { echo "expr2"; } #=> (( 1 > 0 )) || { echo "expr2"; } #=> (( 1 < 0 )) || { echo "expr2"; } #=> expr2
${parameter#word}、${parameter##word} †
- parameterに対しwordで前方一致するパターンを取り除いた結果を返す。#は最短一致、##は最長一致のパターン。
- parameterが@や*の配列変数の場合、全ての要素に対して順番に適用される。
# --- 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
${parameter%word}、${parameter%%word} †
- parameterに対しwordで後方一致するパターンを取り除いた結果を返す。#は最短一致、##は最長一致のパターン。
- parameterが@や*の配列変数の場合、全ての要素に対して順番に適用される。
# --- 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
${parameter/pattern/string} †
- parameterのpatternの最長一致する部分をstringに置換する。
- / で始まる場合は、patternにマッチした全てが置換される。
- # で始まる場合は、parameterを展開した値の先頭にマッチ。
- %で始まる場合は、parameterを展開した値の末尾にマッチ。
- parameterが、@や*の場合は、全ての要素に適用される。
coproc [NAME] command [redirections]
${parameter^pattern}、${parameter^^pattern}、${parameter,pattern}、${parameter,,pattern} †
- parameterに含まれるアルファベットの大文字小文字を変換する。
- ^ は、patternにマッチした小文字を大文字に変換し、, は、大文字を小文字に変換する。これらは、最初にマッチした部分のみ置換する。
- ^^ と ,, は、マッチした全ての文字を置換する。
- parameterが、@や* の場合は、全ての要素に適用される。
# --- 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
参考 https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion
プロセス置換 †
>(list)
は、ファイルへの出力がlistへの入力となる。<(list)
は、listの出力がファイルへの入力となる。
サンプル lsの結果で*.shファイルのみを出力
name () compound-command [ redirections ] function name [()] compound-command [ redirections ]
サンプル a.txtとb.txtをdiffの入力ファイルとして比較
# --- 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
サンプル
# --- 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
execを使った入出力のリダイレクト †
execコマンドでリダイレクトだけを指定すると、シェル自身のファイル記述子とデバイスの対応を変更することができる。
例 execを使った入力のリダイレクト †
# --- commands --- f0() { echo ${FUNCNAME[@]} } f1() { f0 } f2() { f1 } #1 f2 # --- output --- #1 f0 f1 f2 main
例 execを使った出力のリダイレクト †
# --- 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
特定の式や文の出力をまとめてリダイレクトしたい場合は、ブレースを使った複合コマンドでも処理できる。
例 複合コマンドの出力をファイルにリダイレクトする
# --- commands --- function my1() { : } function my2() { : } typeset -f typeset -F # --- output --- my1 () { : } my2 () { : } declare -f my1 declare -f my2