printf를 사용하여 반환 코드를 캡처하고 배열을 정렬합니다.

printf를 사용하여 반환 코드를 캡처하고 배열을 정렬합니다.

현재 잘 작동하는 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

이는 올바른 반환 코드를 전파하는 데 중요합니다.

(댓글 중 하나가 이 내용을 간략하게 언급한 것 같은데, 삭제된 것 같네요)

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배열을 처리하기 위한 두 번째 호출을 쉽게 피할 수 있습니다.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개의 다른 위치에 넣었다는 점에 유의하세요. 쉘, 운영 체제, 인스턴스화 등에 따라 다릅니다. 배치할 정확한 위치를 찾으려면 실험을 해야 할 수도 있습니다.

관련 정보