If-else 매개변수 대체

If-else 매개변수 대체

저는 bash를 사용하여 일련의 실험을 실행 중이며 실험 구성에 따른 이름을 가진 디렉터리에 로그 파일을 저장하고 싶습니다. 구성의 일부 항목은 부울(true/false)입니다. 다음 구성을 예로 들어 보겠습니다.

batch_size=16
fp16=false
bf16=true
checkpoint_activations=true

위에서 구성한 실험 로그 파일을 다음 이름의 디렉터리에 입력으로 저장하고 싶습니다.

output_dir="experiment_bs${batch_size}_dt${fp16 if fp16=true else bf16}_${cp if checkpoint_activations=true else empty}"

물론 보조 변수를 선언할 수도 있습니다.

data_type=""
"${fp16}" && data_type=fp16
"${bf16}" && data_type=bf16
"${cp}" && cp="_cp" || cp=""
output_dir="experiment_bs${batch_size}_dt${data_type}${cp}"

하지만 이건 좀 투박하고 희망적인 것 같아요매개변수 대체여기서 유용할 수도 있습니다. "${bf16:+bf16}"제 경우에는 도움이 되지 않습니다. 정의될 때마다 부울 값에 관계없이 항상 "bf16"을 인쇄하기 때문입니다.

이 사용 사례에 적용할 수 있는 매개변수 대체가 있습니까? 아니면 이 문제에 대한 더 나은 온라인 솔루션이 있습니까?

data_type참고: 내 구성에서 직접 사용 하지 않는 데는 응용 프로그램별 이유가 있습니다 .

답변1

원하는 bash 명령을 넣을 수 있으므로 다음 $(...)과 같이 작성할 수 있습니다.

output_dir="experiment_bs${batch_size}_dt$([[ $fp16 = true ]] && echo $fp16 || echo $bf16)_$([[ $checkpoint_activation = true ]] && echo $cp || echo empty)"

가독성을 위해 다음과 같이 쓸 수도 있습니다.

printf -v output_dir "experiment_bs%s_dt%s_%s" \
  "$batch_size" \
  "$([[ $fp16 = true ]] && echo "$fp16" || echo "$bf16")" \
  "$([[ $checkpoint_activation = true ]] && echo "$cp" || echo empty)"

샘플 입력을 고려하면...

batch_size=16
fp16=false
bf16=true
checkpoint_activations=true

...위의 두 가지 모두 값을 생성합니다.

experiment_bs16_dttrue_empty

답변2

에서는 C를 연상시키는 삼항 연산자 형식(전역 패턴으로 간주되지 않도록 별칭과 함께)을 구현하는 함수를 zsh정의할 수 있습니다 .?? condition if-yes if-nocondition ? if-yes : if-no

alias "?='?'"
'?'() if eval $1; then print -r -- $2; else print -r -- $3; fi

output_dir=experiment_bs${batch_size}_dt$(? $fp16 fp16 bf16)_$(? $cp cp)

zsh 6.0+(2024-02-06 현재 출시되지 않음)의 경우 다음과 같이 변경할 수 있습니다.

alias "?='?'"
'?'() if eval $1; then REPLY=$2; else REPLY=$3; fi

output_dir=experiment_bs${batch_size}_dt${|? $fp16 fp16 bf16}_${|? $cp cp}

결과를 얻기 위해 프로세스를 분기하는 것을 피하고 값이 줄바꿈으로 끝나도록 허용합니다(이 기능을 호출함)발섭(값 대체) mksh에서 복사됨).

삼항 연산자는 첫 번째 인수의 코드를 평가하여 $2or 를 반환할지 여부를 결정하므로 $3해당 $fp16/ 에는 or 가 $cp포함되어야 합니다 . 포함되어 있는지 또는 다른 것이 있는지 확인 하도록 변경하십시오 .truefalse$(? '[[ $fp16 = true ]]' fp16 bp16)$fp16true

당신은 또한 볼 수 있습니다zsh 메일링 리스트에 대한 토론삼항 연산자를 위한 일부 내장 메서드. 그리고이번 Q&A는바르지자세한 내용 및 대안을 확인하세요.

답변3

구성 변수인 경우 해당 구성 변수를 명령으로 변환하므로 fp16이 작업을 수행하지 않을 것입니다 . 누군가가 거기에 비슷한 것을 넣을 가능성을 "${fp16}" && data_type=fp16고려하지 않더라도 오타라도 이상한 모양의 오류 메시지(예: "tru: 명령을 찾을 수 없음" 등)로 이어질 수 있습니다.reboot

그렇다면 이는 다음과 같은 검사기 기능을 사용하여 스크립트가 가져오는 값을 확인하라는 알림일 수도 있습니다.

checkbool() {
    case $1 in
        true|false) return 0;; 
        *) echo >&2 "'$1' is an invalid boolean (must be 'true' or 'false'";
           exit 1;;
    esac
}
checkbool "$fp16"
checkbool "$bf16"
# ...

fp16또한 bf16독립변수로서 의미가 있는지 고려해보세요.

존재하다:

"${fp16}" && data_type=fp16
"${bf16}" && data_type=bf16

과 가 모두 fp16true 인 경우 bf16후자가 우선합니다. 둘 다 설정되지 않은 경우 data_type공백으로 두십시오. 이는 작동할 수도 있고 작동하지 않을 수도 있습니다. 귀하의 구체적인 상황은 잘 모르겠지만 data_type구성 변수로 직접 사용하는 것이 더 나을지 궁금합니다. 글쎄, 게시물에는 직접 사용하지 않을 이유가 있다고 나와 있지만 data_type두 설정이 모두 활성화되거나 둘 중 하나가 활성화되지 않으면 어떻게 될지 생각해 보는 것이 여전히 의미가 있을 수 있습니다.

그럼에도 불구하고 매개변수 확장이 제대로 작동하도록 하려면 "${bf16:+bf16}"null을 false로 사용하고 비어 있지 않은 문자열을 true로 사용해야 합니다. 예를 들어 이 작업을 수행할 수 있지만 data_type="${enable_fp16:+fp16}"다른 값을 유출하지 않고 빈 문자열을 기본값으로 만드는 좋은 방법이 없다고 생각하기 때문에 이것도 사용하기 어려운 것 같습니다. 예를 들어, 반대 작업은 빈 문자열을 로 변환하지만 문자열을 "${enable_fp16:-bf16}"있는 그대로 반환합니다.bf16yes

스크립트에서 null/null이 아닌 값을 사용하는 경우 구성에서 해당 비트의 내부 세부 정보를 사용자에게 노출하시겠습니까? 아니면 구성 값을 스크립트에 실제로 필요한 값으로 변환하기 위해 조건문을 작성하는 것이 더 낫습니까?

저는 다음과 같은 것을 선택하겠습니다. 길게 느껴질 수도 있지만 작성하는 데는 그리 오랜 시간이 걸리지 않습니다. 실제로는 다음과 같습니다.

# config
batch_size=16
fp16=false
bf16=true
checkpoint_activations=true
## code
# this treats anything that's not 'true' as falsy
if   [[ $fp16  = true && $bf16 != true ]]; then
    data_type=fp16
elif [[ $fp16 != true && $bf16  = true ]]; then
    data_type=bf16
else
    echo >&2 "exactly one of fp16 and bf16 must be 'true'"
    exit 1
fi
cp=
if [[ $checkpoint_activations = true ]]; then
    cp=_cp
fi
# (maybe the value of $batch_size should also be checked, whatever

output_dir="experiment_bs${batch_size}_dt${data_type}${cp}"

data_type물론, 각 조건에서 각 입력 변수의 값을 확인하는 대신, 각 할당이 설정되었는지 확인할 수도 있습니다 . (위에서 언급했듯이 세 번째 변수를 추가하려면 기존 조건 두 개를 변경해야 합니다.)

더 깔끔한 접근 방식을 원한다면 Stéphane의 답변에 있는 이중 선택 기능이 Bash에서도 약간 수정되어 작동합니다. 여전히 값을 명시적으로 확인하고 싶지만 다음과 같을 수도 있습니다.

choose() if [[ $1 = true ]]; then printf "%s\n" "$2"
         else printf "%s\n" "$3"
         fi
data_type=$(choose "$fp16" fp16 bf16)
# etc.

물론 길고 명시적인 코드와 간결하고 간결한 코드 사이의 결정은 항상 프로그래머에게 달려 있습니다.

관련 정보