回答編集履歴
4
2020/02/24 19:56 ソースコードの再アップに伴いコメントも記載修正。
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を想定した現時点のソースに再修正致しました。
answer
CHANGED
@@ -25,32 +25,61 @@
|
|
25
25
|
**■ cmn_func.sh**
|
26
26
|
```ここに言語を入力
|
27
27
|
#!/bin/bash
|
28
|
-
set -
|
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
|
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
|
-
|
46
|
+
return 0
|
47
|
+
fi
|
48
|
+
|
35
|
-
A_SrcCode=$
|
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):
|
53
|
+
Msg+=">>>> Script Error Occurred! ($0:$$): \n"
|
38
|
-
|
54
|
+
Msg+="SorceFile: ${BASH_SOURCE[1]} \n"
|
39
|
-
|
55
|
+
Msg+="LineNo(${FUNCNAME[1]}): $L_LineNo \n"
|
56
|
+
if [ ${#RC[@]} -eq 1 ] ; then
|
40
|
-
|
57
|
+
Msg+="Sorce_Code: $A_SrcCode \n"
|
41
|
-
|
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
|
-
|
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
|
76
|
+
trap finary EXIT
|
77
|
+
function finary(){
|
78
|
+
Msg=
|
79
|
+
Msg="=>=>=>=>=>=> Script(${BASH_SOURCE[1]}) finished. ============="
|
80
|
+
echo -e ${Msg}
|
49
81
|
|
50
|
-
#### エラー時も続行させる際の独自メッセージ定義
|
51
|
-
|
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
|
-
|
102
|
+
if [ $RC -ne 0 ] ; then
|
103
|
+
echo -e "サブシェル版例外処理\n"
|
104
|
+
# exit 10
|
105
|
+
fi
|
75
106
|
|
76
|
-
##
|
107
|
+
## 親シェルコマンド
|
77
|
-
|
108
|
+
ls -d $A_dir ; cd $A_dir
|
78
|
-
#
|
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
|
-
|
115
|
+
for val in ${RC[@]} ; do
|
116
|
+
total=$((val + total))
|
117
|
+
done
|
118
|
+
RC=$total
|
82
|
-
|
119
|
+
if [ $RC -ne 0 ] ; then
|
83
|
-
|
120
|
+
echo -e "親シェル版例外処理\n"
|
121
|
+
# exit 10
|
84
|
-
|
122
|
+
fi
|
85
123
|
|
86
|
-
## エラー時も継続させる場合は「||」で繋げてWarn関数を呼び出す(サブシェル版)
|
87
|
-
#(ls $A_dir ; cd $A_dir) || Warn "続行"
|
88
|
-
#if [ ${RC} -ne 0 ] ; then
|
89
|
-
|
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様より頂いた質問に回答する為、現時点のソースに再修正致しました。
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
|
-
|
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
|
51
|
+
function Warn(){
|
40
|
-
|
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
|
-
## エラー時も継続させる場合は「||」で繋げて
|
76
|
+
## エラー時も継続させる場合は「||」で繋げてWarn関数を呼び出す
|
55
|
-
#ls $A_dir ||
|
77
|
+
#ls $A_dir || Warn "続行"
|
56
|
-
#cd $A_dir ||
|
78
|
+
#cd $A_dir || Warn "続行"
|
57
79
|
|
58
|
-
## エラー時も継続させる場合
|
80
|
+
## エラー時も継続させる場合の判定処理
|
59
|
-
#
|
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様より頂いた回答を元にソースを再修正致しました。
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
|
-
|
13
|
+
otn様より頂いた記法がシンプルかつ確実でしたので、使用させて頂きました。
|
15
14
|
|
16
|
-
|
15
|
+
個人的な思いとしては
|
16
|
+
・エラーならとりあえずcatchして独自エラーを吐き、処理をメインに戻す。
|
17
|
+
・継続させたい場合もあるので、終了処理はメイン処理の中で判断して記載する。
|
18
|
+
・なるべくメインシェルには共通関数導入による記法制限をかけたくない。
|
19
|
+
というところがありまして、出来れば「set -E」はつけたくない思いがありました。
|
17
20
|
|
18
|
-
#### 初期化
|
19
|
-
sub_flg=0
|
20
|
-
:>LineNo
|
21
|
-
:>SrcCode
|
22
|
-
|
21
|
+
エラーでも継続させたい場合は「||」で繋げて独自エラー関数を呼び出すような仕組みにしてみました。(これが制約となってしまいましたが・・・)
|
23
22
|
|
24
|
-
#### 各種トラップ
|
25
|
-
trap catch ERR
|
26
|
-
trap finally EXIT
|
27
|
-
function catch() {
|
28
|
-
errcode=$?
|
29
|
-
A_LineNo=`cat LineNo`
|
30
|
-
|
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
|
-
|
25
|
+
```ここに言語を入力
|
39
|
-
|
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
|
-
|
27
|
+
set -ET
|
45
|
-
fi
|
46
28
|
|
29
|
+
#### 各種トラップおよび独自メッセージ定義
|
30
|
+
trap 'catch $LINENO "${BASH_COMMAND}" ; kill $$' ERR
|
31
|
+
function catch(){
|
47
|
-
|
32
|
+
A_LineNo=$1
|
48
|
-
|
33
|
+
A_SrcCode=$2
|
49
|
-
echo $A_LineNo > LineNo
|
50
|
-
|
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
|