現在、うまく機能するbashコードがあります。しかし、構文が少し長いので、次のbashコードを減らす方法についての提案をいただきありがとうございます。
完全な参照のために、スクリプト全体がここにあります。https://gist.github.com/sacvalleytech/951f9eb98625f983f8f4dab623f5918b
# find new deps
# $1 -> file to search for dependencies
# $2 -> array of previous dependency changes (from siblings; used to invalidate cache); code not shown
# $3 -> hierarchy of dependencies (for circular ref checking); code not shown
DEP_OUT=( "$(changes "$DEP" "${DEP_OUT[*]}" "${DEP_HIERARCHY[*]}")" )
# >>> its really annoying to do this
# >>> to capture the return code before sorting the array
# >>> sorting the array BEFORE causes the return code to be lost
[ "$?" -eq 0 ] && DEP_CHANGED=true
# sort values | normalize paths | uniq values
DEP_OUT=( $(printf "%s\n" "${DEP_OUT[@]}" | sort | trim | uniq) )
修正する:
意見に基づいて、次の解決策を思い出しました。
function format_array {
if [ -t 0 ]; then
local ARRAY_IN=( $@ )
else
readarray ARRAY_ARGS < /dev/stdin
local ARRAY_IN=( $@ ${ARRAY_ARGS[@]} )
fi
echo $(printf "%s\n" "${ARRAY_IN[@]}" | sort | normalize_paths | uniq)
}
shopt -s lastpipe
shopt -so pipefail
DEP_OUT=( $(changes "$DEP" "${DEP_OUT[*]}" "${DEP_HIERARCHY[*]}" | format_array "${DEP_OUT[*]}") ) && \
DEP_CHANGED=true
これは正しい戻りコードを伝播するために重要です。
(コメントの1つがこの内容を簡単に言及したようですが、削除されたようですね)
shopt -s lastpipe
shopt -so pipefail
答え1
再帰関数内で使用されるコードを単純化しようとしています。
改善したいのは、関数の終了コードをキャプチャすることです。
戻りコードは次のとおりです。いいえ情報を伝達する唯一の方法です。実際に情報を渡す最速の方法は、変数を使用することです。再帰関数では、親が値を再読み込みできるように、グローバル変数(ローカル変数として定義されていない)でなければなりません。この例では、戻りコードを1に設定する行は次のとおりです。
# return 1 (false) if $DEP_CHANGED = false && $DEP_FILE is cached
[ "$DEP_CHANGED" = false ] && (cached "$(dirname "$DEP_FILE")") && return 1
次のように変更できます。
# Inform that data didn't change
[ "$DEP_CHANGED" = false ] &&
(cached "$(dirname "$DEP_FILE")") &&
dep_changed_in_function=false
そしてそれに応じて:
for DEP in "${DEP_LIST[@]}"; do
dep_changed_in_function=true
# find new deps
DEP_OUT=( "$(changes "$DEP" "${DEP_OUT[*]}" "${DEP_HIERARCHY[*]}")" )
DEP_OUT=( $(printf "%s\n" "${DEP_OUT[@]}" | sort | trim | uniq) )
# set $DEP_CHANGED flag
[ "$dep_changed_in_function" -eq true ] && DEP_CHANGED=true
done
ただし、データ出力がすでにソートされている場合は、配列を処理DEP_OUT
するための2番目の呼び出しを簡単に回避できます。changes
これは次の方法で簡単に行うことができます。
echo $(printf '%s\n' "${DEP_OUT[@]}" | sort | trim | uniq )
変える
echo "${DEP_OUT[@]}"
これにより、質問のコードセクションが次のように減少します。
for DEP in "${DEP_LIST[@]}"; do
dep_changed_in_function=true
DEP_OUT=( "$(changes "$DEP" "${DEP_OUT[*]}" "${DEP_HIERARCHY[*]}")" )
# set $DEP_CHANGED flag
DEP_CHANGED=$dep_changed_in_function
done
もちろん、dep_changed_in_function=true
これは関数の先頭で設定できます。
答え2
これを見たことがあります。はい、ちょっと迷惑です。
ヒントは、戻りコードを変更できる他のコマンドを実行する前に、変更された戻りコードを取得することです。
私は次のことを試してみます:
DEP_OUT=( "$(changes "$DEP" "${DEP_OUT[
*
]}" "${DEP_HIERARCHY[]}")"; rc=$? )
または
DEP_OUT=( "$(changes "$DEP" "${DEP_OUT[
*
]}" "${DEP_HIERARCHY[]}")" );rc=$?
それから$?代わりに $rc を使用してください。
[ $rc -eq 0 ] && DEP_CHANGED=true
これがうまくいけば、すべてを組み合わせることができます。
DEP_OUT=( "$(changes "$DEP" "${DEP_OUT[
*
]}" "${DEP_HIERARCHY[*]}";rc=$? )" | sort | trim | uniq)
rc=$? を 3 つの異なる場所に置いたことに注意してください。シェル、オペレーティングシステム、インスタンス化などによって異なります。配置する正確な場所を見つけるために実験を行う必要があるかもしれません。