teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

4

2020/02/24 19:56 ソースコードの再アップに伴いコメントも記載修正。

2020/02/24 10:59

投稿

gaccha
gaccha

スコア6

answer CHANGED
@@ -10,18 +10,28 @@
10
10
  ~~仕方がないので一旦ファイルに変数の値を吐き出してゴニョゴニョすることとしました。~~
11
11
  ~~より良い方法があればご教示頂けると幸いです。~~
12
12
 
13
- otn様より頂いた記法がシンプルかつ確実でしたので、使用させて頂きました。
13
+ ~~otn様より頂いた記法がシンプルかつ確実でしたので、使用させて頂きました。~~
14
14
 
15
- 個人的な思いとしては
15
+ ~~個人的な思いとしては
16
16
  ・エラーならとりあえずcatchして独自エラーを吐き、処理をメインに戻す。
17
- ・継続させたい場合もあるので、終了処理はメイン処理の中で判断して記載する。
17
+ ・継続させたい場合もあるので、終了処理はメイン処理の中で判断して記載する。~~
18
- ・なるべくメインシェルには共通関数導入による記法制限をかけたくない。
18
+ ~~・なるべくメインシェルには共通関数導入による記法制限をかけたくない。
19
19
  というところがありまして、出来れば「set -E」はつけたくない思いがありました。
20
+ ~~
21
+ ~~エラーでも継続させたい場合は「||」で繋げて独自エラー関数を呼び出すような仕組みにしてみました。(これが制約となってしまいましたが・・・)
22
+ ~~
20
23
 
24
+ 2020/02/24 19:56 : 記載修正、シェル再アップ
21
- エラーでも継続させたい場合は「||」で繋げて独自エラー関数呼び出すような仕組みにしてみまし。(これ制約となってしまいましたが・・・)
25
+ otn様とやりとり重ね結果、当初と実装手法となりまたので最終版をアップしました
22
-
23
26
  とても助かりました!ありがとうございました!
24
27
 
28
+ ・「set -E」でサブシェル内の処理までERRトラップが行われる。
29
+  ※「set -e」とは異なり、エラー終了はされない。
30
+ ・上記注釈記載により「||」による実装制約は解消。ただし、コマンドエラーの結果はcatch()で処理するようにしているため、実装処理では一律$RCでステータスコードを取る制約とする。
31
+ ・サブシェルでERRトラップした場合、親シェルでもう一度ERRトラップが走ってしまい、余計なメッセージが出力されてしまう為、catch()内で「サブシェル→親シェル」に戻ったかを判定する処理を実装。(サブシェルでセットした変数の値は親シェルに引き継がれない為、ファイルで管理)
32
+ ・パイプラインのエラーに対応する為、「set -o pipefail」を追加。
33
+ ・シェルを共通関数「cmn_func.sh」と実装シェル「main_shell.sh」に分離。
34
+
25
35
  **■ cmn_func.sh**
26
36
  ```ここに言語を入力
27
37
  #!/bin/bash

3

2020/02/24 19:45 サブシェル対応およびpipelineを想定した現時点のソースに再修正致しました。

2020/02/24 10:59

投稿

gaccha
gaccha

スコア6

answer CHANGED
@@ -25,32 +25,61 @@
25
25
  **■ cmn_func.sh**
26
26
  ```ここに言語を入力
27
27
  #!/bin/bash
28
- set -ET
28
+ set -E -o pipefail
29
29
 
30
+ #### 初期化処理
31
+ RC=0
32
+ echo 0 > SUBSHELL
33
+
34
+ #### 処理開始メッセージ
35
+ Msg="============ Script(${BASH_SOURCE[1]}) be in started. =>=>=>=>"
36
+ echo -e ${Msg}
37
+
30
38
  #### 各種トラップおよび独自メッセージ定義
31
- trap 'catch $LINENO "${BASH_COMMAND}" ; kill $$' ERR
39
+ trap 'catch "${BASH_COMMAND}"' ERR
32
40
  function catch(){
33
41
  RC=(${PIPESTATUS[@]})
42
+
43
+ ## サブシェル対応(現時点が親シェルの場合、サブシェルから復帰しているか確認)
44
+ if [ $BASH_SUBSHELL -eq 0 -a `cat SUBSHELL` -ne 0 ] ; then
45
+ echo $BASH_SUBSHELL > SUBSHELL
34
- A_LineNo=$1
46
+ return 0
47
+ fi
48
+
35
- A_SrcCode=$2
49
+ A_SrcCode=$1
50
+ L_LineNo=$BASH_LINENO
36
51
  L_ExecCMD=`eval "echo $A_SrcCode"`
52
+ Msg=
37
- Msg=">>>> Script Error Occurred! ($0): \n\
53
+ Msg+=">>>> Script Error Occurred! ($0:$$): \n"
38
- SorceFile: ${BASH_SOURCE[1]} \n\
54
+ Msg+="SorceFile: ${BASH_SOURCE[1]} \n"
39
- LineNo(${FUNCNAME[1]}): $A_LineNo \n\
55
+ Msg+="LineNo(${FUNCNAME[1]}): $L_LineNo \n"
56
+ if [ ${#RC[@]} -eq 1 ] ; then
40
- Sorce_Code: $A_SrcCode \n\
57
+ Msg+="Sorce_Code: $A_SrcCode \n"
41
- Execute_CMD: $L_ExecCMD \n\
58
+ Msg+="Execute_CMD: $L_ExecCMD \n"
59
+ else
60
+ Msg+="Sorce_Code: $A_SrcCode ( Pipeline be in used. Please check one lines. ) \n"
61
+ Msg+="Execute_CMD: $L_ExecCMD ( Pipeline be in used. Please check one lines. ) \n"
62
+ fi
63
+ Msg+="Sub_Shell: $BASH_SUBSHELL \n"
42
- Exited with status: ${RC[@]}."
64
+ Msg+="Exited with status: ${RC[@]}."
43
65
  echo -e ${Msg}
44
66
  echo
45
67
 
68
+ ## サブシェル対応(判定処理の為に、現在のサブシェル状態をファイルへ書き込み)
69
+ if [ $BASH_SUBSHELL -ne 0 ] ; then
70
+ echo $BASH_SUBSHELL > SUBSHELL
71
+ fi
72
+
46
73
  }
47
74
 
75
+ #### 終了処理
48
- trap 'echo FINALLY' EXIT
76
+ trap finary EXIT
77
+ function finary(){
78
+ Msg=
79
+ Msg="=>=>=>=>=>=> Script(${BASH_SOURCE[1]}) finished. ============="
80
+ echo -e ${Msg}
49
81
 
50
- #### エラー時も続行させる際の独自メッセージ定義
51
- function Warn(){
82
+ rm SUBSHELL
52
- RC=(${PIPESTATUS[@]})
53
- echo $1
54
83
  }
55
84
  ```
56
85
 
@@ -63,34 +92,36 @@
63
92
 
64
93
  #### メイン
65
94
  ## 事前処理
66
- echo pre
95
+ echo -e "pre \n"
67
96
  A_dir=$1
68
97
 
69
- ## エラーで落とす場合はコマンド記載のみ
98
+ ## サブシェルコマンド
70
- ls $A_dir ; cd $A_dir
99
+ (ls -d $A_dir ; cd $A_dir)
71
- #tar cvf - -C $A_dir | tar xvf $A_dir
72
100
 
73
- ## エラーで落とす場合はコマンド記載のみ(サブシェル
101
+ ## 判定を入れて例外処理や終了処理を入れる(サブシェル)
74
- #(ls $A_dir ; cd $A_dir)
102
+ if [ $RC -ne 0 ] ; then
103
+ echo -e "サブシェル版例外処理\n"
104
+ # exit 10
105
+ fi
75
106
 
76
- ## エラー時も継続させる場合は「||」で繋げてWarn関数を呼び出す
107
+ ## 親シェルコマンド
77
- #ls $A_dir || Warn "続行"
108
+ ls -d $A_dir ; cd $A_dir
78
- #cd $A_dir || Warn "続行"
109
+ #ls -d ${A_dir} | xargs -I {} echo "Current Directory is {}." # パイプラインエラーテスト X | 0
110
+ #echo "test" | xargs ls -d # パイプラインエラーテスト 0 | X
111
+ #ls -d ${A_dir} | xargs cd # パイプラインエラーテスト X | X
79
112
 
80
- ## エラー時も継続させる場合の判定処理
113
+ ## 判定を入れて例外処理や終了処理を入れる(親シェル)
114
+ total=0
81
- #tar cvf - -C $A_dir | tar xvf $A_dir || Warn "続行"
115
+ for val in ${RC[@]} ; do
116
+ total=$((val + total))
117
+ done
118
+ RC=$total
82
- #if [ ${RC[0]} -ne 0 ] ; then
119
+ if [ $RC -ne 0 ] ; then
83
- # echo "リターンコードに応じた例外処理"
120
+ echo -e "親シェル版例外処理\n"
121
+ # exit 10
84
- #fi
122
+ fi
85
123
 
86
- ## エラー時も継続させる場合は「||」で繋げてWarn関数を呼び出す(サブシェル版)
87
- #(ls $A_dir ; cd $A_dir) || Warn "続行"
88
- #if [ ${RC} -ne 0 ] ; then
89
- # echo "リターンコードに応じた例外処理"
124
+ echo -e "post \n"
90
- #fi
91
125
 
92
-
93
- echo post
94
-
95
126
  exit 0
96
127
  ```

2

2020/02/23 21:11 otn様より頂いた質問に回答する為、現時点のソースに再修正致しました。

2020/02/24 10:27

投稿

gaccha
gaccha

スコア6

answer CHANGED
@@ -22,6 +22,7 @@
22
22
 
23
23
  とても助かりました!ありがとうございました!
24
24
 
25
+ **■ cmn_func.sh**
25
26
  ```ここに言語を入力
26
27
  #!/bin/bash
27
28
  set -ET
@@ -29,36 +30,66 @@
29
30
  #### 各種トラップおよび独自メッセージ定義
30
31
  trap 'catch $LINENO "${BASH_COMMAND}" ; kill $$' ERR
31
32
  function catch(){
33
+ RC=(${PIPESTATUS[@]})
32
34
  A_LineNo=$1
33
35
  A_SrcCode=$2
36
+ L_ExecCMD=`eval "echo $A_SrcCode"`
34
- echo "Error line:$A_LineNo sorce_code:\"$A_SrcCode\" exited with status $?."
37
+ Msg=">>>> Script Error Occurred! ($0): \n\
38
+ SorceFile: ${BASH_SOURCE[1]} \n\
39
+ LineNo(${FUNCNAME[1]}): $A_LineNo \n\
40
+ Sorce_Code: $A_SrcCode \n\
41
+ Execute_CMD: $L_ExecCMD \n\
42
+ Exited with status: ${RC[@]}."
43
+ echo -e ${Msg}
44
+ echo
45
+
35
46
  }
47
+
36
48
  trap 'echo FINALLY' EXIT
37
49
 
38
50
  #### エラー時も続行させる際の独自メッセージ定義
39
- function LogMsg(){
51
+ function Warn(){
40
- true
52
+ RC=(${PIPESTATUS[@]})
41
53
  echo $1
42
54
  }
55
+ ```
43
56
 
57
+ **■ main_shell.sh**
58
+ ```ここに言語を入力
59
+ #!/bin/bssh
60
+
61
+ #### 共通関数読み込み
62
+ . ./cmn_func.sh
63
+
44
64
  #### メイン
65
+ ## 事前処理
45
66
  echo pre
46
67
  A_dir=$1
47
68
 
48
69
  ## エラーで落とす場合はコマンド記載のみ
49
70
  ls $A_dir ; cd $A_dir
71
+ #tar cvf - -C $A_dir | tar xvf $A_dir
50
72
 
51
73
  ## エラーで落とす場合はコマンド記載のみ(サブシェル版)
52
74
  #(ls $A_dir ; cd $A_dir)
53
75
 
54
- ## エラー時も継続させる場合は「||」で繋げてLogMsg関数を呼び出す
76
+ ## エラー時も継続させる場合は「||」で繋げてWarn関数を呼び出す
55
- #ls $A_dir || LogMsg "続行"
77
+ #ls $A_dir || Warn "続行"
56
- #cd $A_dir || LogMsg "続行"
78
+ #cd $A_dir || Warn "続行"
57
79
 
58
- ## エラー時も継続させる場合は「||」で繋げてLogMsg関数を呼び出す(サブシェル版)
80
+ ## エラー時も継続させる場合の判定処理
59
- #(ls $A_dir ; cd $A_dir) || LogMsg "続行"
81
+ #tar cvf - -C $A_dir | tar xvf $A_dir || Warn "続行"
82
+ #if [ ${RC[0]} -ne 0 ] ; then
83
+ # echo "リターンコードに応じた例外処理"
84
+ #fi
60
85
 
86
+ ## エラー時も継続させる場合は「||」で繋げてWarn関数を呼び出す(サブシェル版)
87
+ #(ls $A_dir ; cd $A_dir) || Warn "続行"
88
+ #if [ ${RC} -ne 0 ] ; then
89
+ # echo "リターンコードに応じた例外処理"
90
+ #fi
61
91
 
92
+
62
93
  echo post
63
94
 
64
95
  exit 0

1

otn様より頂いた回答を元にソースを再修正致しました。

2020/02/23 12:17

投稿

gaccha
gaccha

スコア6

answer CHANGED
@@ -1,66 +1,64 @@
1
- 上記修正の上、色々と検証した結果、変数のスコープが問題のようでした。
1
+ ~~上記修正の上、色々と検証した結果、変数のスコープが問題のようでした。~~
2
2
 
3
- ・サブシェル実行時には以下の通りとなります
3
+ ~~・サブシェル実行時には以下の通りとなります~~
4
- A_SrcCode='cd $A_dir'
4
+ ~~A_SrcCode='cd $A_dir'~~
5
5
 
6
- ・しかし、親に処理が戻るとサブシェルが設定した値は破棄される為、前回実行したコマンドの結果が残っています。
6
+ ~~・しかし、親に処理が戻るとサブシェルが設定した値は破棄される為、前回実行したコマンドの結果が残っています。~~
7
- A_SrcCode='echo 'no sach directory.'
7
+ ~~A_SrcCode='echo 'no sach directory.'~~
8
8
 
9
9
 
10
- 仕方がないので一旦ファイルに変数の値を吐き出してゴニョゴニョすることとしました。
10
+ ~~仕方がないので一旦ファイルに変数の値を吐き出してゴニョゴニョすることとしました。~~
11
- より良い方法があればご教示頂けると幸いです。
11
+ ~~より良い方法があればご教示頂けると幸いです。~~
12
12
 
13
- ```ここに言語を入力
14
- #!/bin/bssh
13
+ otn様より頂いた記法がシンプルかつ確実でしたので、使用させて頂きました。
15
14
 
16
- set -T
15
+ 個人的な思いとしては
16
+ ・エラーならとりあえずcatchして独自エラーを吐き、処理をメインに戻す。
17
+ ・継続させたい場合もあるので、終了処理はメイン処理の中で判断して記載する。
18
+ ・なるべくメインシェルには共通関数導入による記法制限をかけたくない。
19
+ というところがありまして、出来れば「set -E」はつけたくない思いがありました。
17
20
 
18
- #### 初期化
19
- sub_flg=0
20
- :>LineNo
21
- :>SrcCode
22
- echo 0 > SubShell
21
+ エラーでも継続させたい場合は「||」で繋げて独自エラー関数を呼び出すような仕組みにしてみました。(これが制約となってしまいましたが・・・)
23
22
 
24
- #### 各種トラップ
25
- trap catch ERR
26
- trap finally EXIT
27
- function catch() {
28
- errcode=$?
29
- A_LineNo=`cat LineNo`
30
- A_SrcCode=`cat SrcCode`
23
+ とても助かりました!ありがとうございました!
31
- echo "error line:$A_LineNo sorce_code:\"$A_SrcCode\" exited with status $errcode."
32
- exit 8
33
- }
34
- function finally() {
35
- echo FINALLY
36
- }
37
24
 
38
- trap 'trace $LINENO "${BASH_COMMAND}"' DEBUG
25
+ ```ここに言語を入力
39
- function trace() {
26
+ #!/bin/bash
40
- if [ $? -ne 0 ] ; then return ; fi
41
- if [ ${FUNCNAME[1]} == "catch" ] ; then return ; fi
42
- if [ `cat SubShell` -ne 0 -a $BASH_SUBSHELL -eq 0 ] ; then
43
- echo $BASH_SUBSHELL > flg
44
- return
27
+ set -ET
45
- fi
46
28
 
29
+ #### 各種トラップおよび独自メッセージ定義
30
+ trap 'catch $LINENO "${BASH_COMMAND}" ; kill $$' ERR
31
+ function catch(){
47
- A_LineNo=$1
32
+ A_LineNo=$1
48
- A_SrcCode=$2
33
+ A_SrcCode=$2
49
- echo $A_LineNo > LineNo
50
- echo "${A_SrcCode}" > SrcCode
34
+ echo "Error line:$A_LineNo sorce_code:\"$A_SrcCode\" exited with status $?."
51
- echo ${BASH_SUBSHELL} > SubShell
52
35
  }
36
+ trap 'echo FINALLY' EXIT
53
37
 
38
+ #### エラー時も続行させる際の独自メッセージ定義
39
+ function LogMsg(){
40
+ true
41
+ echo $1
42
+ }
43
+
54
- ##### メイン
44
+ #### メイン
55
45
  echo pre
56
-
57
46
  A_dir=$1
58
- if [ ! -d $A_dir ] ; then
59
- echo "no sach directory."
60
- fi
61
47
 
48
+ ## エラーで落とす場合はコマンド記載のみ
62
- cd $A_dir
49
+ ls $A_dir ; cd $A_dir
63
50
 
51
+ ## エラーで落とす場合はコマンド記載のみ(サブシェル版)
52
+ #(ls $A_dir ; cd $A_dir)
53
+
54
+ ## エラー時も継続させる場合は「||」で繋げてLogMsg関数を呼び出す
55
+ #ls $A_dir || LogMsg "続行"
56
+ #cd $A_dir || LogMsg "続行"
57
+
58
+ ## エラー時も継続させる場合は「||」で繋げてLogMsg関数を呼び出す(サブシェル版)
59
+ #(ls $A_dir ; cd $A_dir) || LogMsg "続行"
60
+
61
+
64
62
  echo post
65
63
 
66
64
  exit 0