단일 행 셸 할당, 그러나 변수가 설정되지 않은 경우에만 해당(null 또는 빈 값 고려)?

단일 행 셸 할당, 그러나 변수가 설정되지 않은 경우에만 해당(null 또는 빈 값 고려)?

다른 경우에는 APP_ENV"prod"가 비어 있어야 합니다.DATABASE_DISABLE_MIGRATIONStrue ~하지 않는 한 DATABASE_DISABLE_MIGRATIONS비어 있거나 null입니다. 즉, 그것은가치는 존중되어야합니다자동 할당은 다음과 같은 경우에만 발생해야 합니다.설정되지 않음.

원래DATABASE_DISABLE_MIGRATIONS APP_ENV 새로운DATABASE_DISABLE_MIGRATIONS
비어 있거나 비어 있음 어느 원래의 가치를 유지하다
길이가 0이 아닌 문자열 어느 원래의 가치를 유지하다
설정되지 않음 "제품" 비어 있는
설정되지 않음 비어 있거나 "prod"가 아님 "진짜"

저는 쉘(POSIX)을 배우기 시작했고 다음 코드를 사용하여 이 작업을 성공적으로 수행했습니다.

#!/bin/sh

if [ "${DATABASE_DISABLE_MIGRATIONS+set}" != set ]; then
    : ${DATABASE_DISABLE_MIGRATIONS:=$( [ "$APP_ENV" = "prod" ] || echo "true" )}
fi

# Just for debug (not meant to be in the single-line assignment of course)
if [ -z "$DATABASE_DISABLE_MIGRATIONS" ]; then
    echo "Empty value, migrations ENABLED"
else
    echo "Not empty value, migrations DISABLED"
fi

위 코드를 한 줄짜리 문장으로 작성할 수 있나요?

설정되지 않은 문자열, null 또는 빈 문자열을 고려할 때 한 줄짜리 명령문을 만드는 것은 쉽습니다. 저는 종종 다음을 사용하게 됩니다.

: ${FOO:=$( [ "$APP_ENV" = "prod" ] || echo "true" )}

변수는 설정되지 않은 경우, null이거나 비어 있고 "prod"가 아닌 경우 FOO값을 가져옵니다 .trueFOOAPP_ENV

어쩌면 비슷한 "바로가기"가 누락된 것일까요?

여기에 이미지 설명을 입력하세요.

답변1

2개의 변수를 사용하는 Case 문은 다음과 같습니다.

case "${DATABASE_DISABLE_MIGRATIONS}:${APP}" in
    ?*:* | "":prod) # not empty, or prod
                    echo "Not empty value, migrations DISABLED"
                    ;;
    *) echo "Empty value, migrations ENABLED"
       ;;
esac

하지만 이는 "비어 있음"과 "설정되지 않음"을 구분하지 않습니다. 변수 값 중 하나에 콜론이 포함되어 있는 경우에도 스푸핑될 가능성이 있습니다.


기반으로

원래DATABASE_DISABLE_MIGRATIONS APP_ENV 새로운DATABASE_DISABLE_MIGRATIONS
비어 있거나 비어 있음 어느 원래의 가치를 유지하다
길이가 0이 아닌 문자열 어느 원래의 가치를 유지하다
설정되지 않음 "제품" 비어 있는
설정되지 않음 비어 있거나 "prod"가 아님 "진짜"

자신을 POSIX로 제한하지 마십시오. "설정되지 않음"은조정변수를 사용하려면 다음을 수행합니다.

if [[ ! -v DATABASE_DISABLE_MIGRATIONS ]]; then
    if [[ $APP == prod ]]; then 
        DATABASE_DISABLE_MIGRATIONS=""
    else
        DATABASE_DISABLE_MIGRATIONS=true
    fi
fi

이는 분명히 귀하의 한 줄 희망 사항을 충족시키지 못하지만 귀하의 의도를 전달하는 가장 읽기 쉬운 방법이라고 생각합니다.

답변2

주문하다:

[ -z "${DATABASE_DISABLE_MIGRATIONS+x}" ] && [ "$APP_ENV" != "prod" ] && DATABASE_DISABLE_MIGRATIONS=true

설명하다:

논평이 정보를 사용하여 변수를 확인함을 나타냅니다.
[ -z "$DATABASE_DISABLE_MIGRATIONS" ]
이 정보는 질문의 일부여야 합니다.

"$DATABASE_DISABLE_MIGRATIONS"(또는)을 사용하지 않는 한 set -u, 설정되지 않은 변수나 빈 문자열에 대해 확장 결과가 동일하므로 set -o nounset요구 사항이 단순화됩니다. 설정되지 않은 변수를 명시적인 null 값으로 바꾸지 마십시오. "prod"설정하지 않은 채로 두면 동일한 테스트 결과를 얻을 수 있기 때문입니다.

따라서 알고리즘은 다음과 같이 단순화될 수 있습니다.

  • (DATABASE_DISABLE_MIGRATIONS가 설정되지 않고 APP_ENV가 "prod"가 아닌 경우) DATABASE_DISABLE_MIGRATIONS를 "true"로 설정합니다.
  • (그렇지 않으면 아무것도 하지 않음)

물론 이것을 여러 줄로 작성할 수 있으므로 코드가 더 명확해 지지만 한 줄이 아니며 질문에 대한 솔루션보다 훨씬 짧지 않습니다.

if [ -z "${DATABASE_DISABLE_MIGRATIONS+x}" ] && [ "$APP_ENV" != "prod" ]
then
    DATABASE_DISABLE_MIGRATIONS=true
fi

답변3

따라서 변수가 설정되지 않은 경우 기본값으로 설정하고 그렇지 않으면 원래 값을 유지하시겠습니까? (여기서 기본값은 다른 변수에 따라 다르지만 이로 인해 산만해지지 않도록 합시다.)

그렇다면 다음과 같이 하는 것이 더 나을 수도 있습니다.

# don't disable migrations in production by default
if [ "$APP_ENV" = prod ]; then
    default_DATABASE_DISABLE_MIGRATIONS=
else
    default_DATABASE_DISABLE_MIGRATIONS=true
fi
# set default value if unset
if [ "${DATABASE_DISABLE_MIGRATIONS+set}" != set ]; then
    DATABASE_DISABLE_MIGRATIONS=$default_DATABASE_DISABLE_MIGRATIONS
fi

또는 더 짧은 것:

# don't disable migrations in production by default
default_DATABASE_DISABLE_MIGRATIONS=true
if [ "$APP_ENV" = prod ]; then
    default_DATABASE_DISABLE_MIGRATIONS=
fi
# set default value if unset
: "${DATABASE_DISABLE_MIGRATIONS=$default_DATABASE_DISABLE_MIGRATIONS}"

관련 값을 기반으로 한 코드 골프는 다른 값에 대해서도 비슷한 로직을 사용해야 한다면 전체 코드를 수정해야 하기 때문에 비생산적인 것 같습니다. 다른 유사한 사례에 적용할 수 있는 간단한 솔루션을 개발하는 것이 좋습니다. 마지막 줄은 질문 제목에서 요청한 것과 거의 비슷하지만 변수가 설정되지 않은 경우 한 줄의 셸 할당만 수행합니다. ( "${var:=default}"빈 값 집합에도 작동합니다.)

또한 최종 변수가 부정되지 않으면 독자에게 더 명확해질 수 있다는 점도 지적하고 싶습니다. [ -z "$DATABASE_DISABLE_MIGRATIONS" ]기본적으로 "마이그레이션이 비활성화되지 않은 경우"와 같은 변수 사용 및 테스트를 언급했습니다 . 이는 "마이그레이션이 활성화된 경우"와 동일하며 변수를 사용하면 작성하기가 더 쉽습니다 $DATABASE_ENABLE_MIGRATIONS.

답변4

가능한:

case ${DATABASE_DISABLE_MIGRATIONS++}:$APP_ENV in
  (:prod) DATABASE_DISABLE_MIGRATIONS=    ;;
  (:*   ) DATABASE_DISABLE_MIGRATIONS=true;;
esac

다른 코드와 마찬가지로 한 줄에 넣고 줄을 연결하거나 다음과 같이 압축할 수도 있습니다.

case ${DATABASE_DISABLE_MIGRATIONS++}:$APP_ENV in(:prod)DATABASE_DISABLE_MIGRATIONS=;;(:*)DATABASE_DISABLE_MIGRATIONS=true;esac

) 그러나 나는 이점을 보지 못했습니다.

실행은 $(... echo ...)추가 프로세스를 분기하고(ksh93 제외) echo명령을 실행하고 파이프를 통해 해당 명령을 보내고 받는 것을 의미합니다. 이는 수십만 개 이상의 CPU 명령을 의미하는 반면, 이러한 간단한 셸 할당 및 패턴 일치는 단지 수백 개가 있습니다. , 그래서 나에게는 조금 어리석은 느낌이 듭니다.

관련 정보