저는 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-no
condition ? 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에서 복사됨).
삼항 연산자는 첫 번째 인수의 코드를 평가하여 $2
or 를 반환할지 여부를 결정하므로 $3
해당 $fp16
/ 에는 or 가 $cp
포함되어야 합니다 . 포함되어 있는지 또는 다른 것이 있는지 확인 하도록 변경하십시오 .true
false
$(? '[[ $fp16 = true ]]' fp16 bp16)
$fp16
true
당신은 또한 볼 수 있습니다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
과 가 모두 fp16
true 인 경우 bf16
후자가 우선합니다. 둘 다 설정되지 않은 경우 data_type
공백으로 두십시오. 이는 작동할 수도 있고 작동하지 않을 수도 있습니다.
귀하의 구체적인 상황은 잘 모르겠지만 글쎄, 게시물에는 직접 사용하지 않을 이유가 있다고 나와 있지만 data_type
구성 변수로 직접 사용하는 것이 더 나을지 궁금합니다.data_type
두 설정이 모두 활성화되거나 둘 중 하나가 활성화되지 않으면 어떻게 될지 생각해 보는 것이 여전히 의미가 있을 수 있습니다.
그럼에도 불구하고 매개변수 확장이 제대로 작동하도록 하려면 "${bf16:+bf16}"
null을 false로 사용하고 비어 있지 않은 문자열을 true로 사용해야 합니다. 예를 들어 이 작업을 수행할 수 있지만 data_type="${enable_fp16:+fp16}"
다른 값을 유출하지 않고 빈 문자열을 기본값으로 만드는 좋은 방법이 없다고 생각하기 때문에 이것도 사용하기 어려운 것 같습니다. 예를 들어, 반대 작업은 빈 문자열을 로 변환하지만 문자열을 "${enable_fp16:-bf16}"
있는 그대로 반환합니다.bf16
yes
스크립트에서 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.
물론 길고 명시적인 코드와 간결하고 간결한 코드 사이의 결정은 항상 프로그래머에게 달려 있습니다.