그래서 나는 이것을 가지고 있습니다 :
export ti_arg='';
if [[ -t 1 ]] ; then
# allow us to kill container if attached to terminal
export ti_arg='-ti'
fi
(
cd "$(dirname "$BASH_SOURCE")"
docker build <...> '.'
docker run "$ti_arg" --rm "test-$commit_id"
)
문제는 $ti_arg가 비어 있음에도 불구하고 쉘이 이를 인수로 처리하여 다음과 같은 결과를 얻는다는 것입니다.
docker: 잘못된 참조 형식
내가 생각할 수 있는 유일한 해결책은 기본적으로 동일한 if/else docker 명령(해당 인수 제외)을 실행하거나 다음과 같이 docker와 함께 사용할 수 있는 전달 인수를 찾는 것입니다.
export ti_arg='--noop';
if [[ -t 1 ]] ; then
# allow us to kill container if attached to terminal
export ti_arg='-ti'
fi
누구든지 좋은 해결책을 가지고 있습니까? CLI 디자인은 항상 --noop
이 사용 사례에 대한 플래그를 제공 할 것 같습니다.
답변1
그것을 처리하는 방법에는 여러 가지가 있습니다. 기본 접근 방식은 쉘의 기능을 사용하여 설정 중인 매개변수를 테스트하는 것입니다. 그래서 당신은 가질 수 있습니다
docker run ${ti_arg:+"$ti_arg"} --rm "test-$commit_id"
이는 ti_arg가 설정되어 있는지 테스트하고, 그렇다면 이를 에 넣습니다 "$ti_arg"
.
물론 시작 스크립트가 export ti_arg=''
최고는 아닙니다. 이는 매개변수 값이 빈 문자열임을 명시적으로 의미합니다. 값이 설정되지 않았다고 말하는 것이 더 나을 것입니다 unset ti_arg
. 하지만 이 경우에는 문제가 해결되지 않습니다. 그러나 값을 설정하지 않은 상황을 더 잘 표현하기 위해 를 사용할 수 있습니다 ${ti_arg+"$ti_arg"}
( 가 없음에 유의 ).:
'$@' 사용 팁
다행히도 오래전부터 사람들은
subprog ${1:"$@"}
이 문제를 해결하려면 스크립트에서 매개변수 확장을 처리하세요. Bourne의 모든 최신 구현(예: 쉘)에서는 이 버그가 수정되었으므로 (큰따옴표로) 그냥 말할 수 "$@"
있으며 값이 설정되지 않은 경우 올바르게 null로 확장됩니다. 따라서 명명된 변수를 사용하는 대신 다음을 사용할 수 있습니다.
set -- # Clear the $@ array
if [[ -t 1 ]] ; then
set -- "-ti"
fi
...
docker run "$@" --rm ....
C 프로그래머를 위한 참고 사항
익숙한 분들을 위해 C
설정되지 않은 변수와 빈 문자열로 설정되는 것의 차이점은 다음과 같습니다.
char *var = NULL; /* unset case. var is 4 or 8 bytes all of which are 0 */
char *var = strdup(""); /* set to the empty string. var is still 4 or 8 8 bytes, but now contains the address of an item in the heap, which could be as small as 1 byte. The first byte of this heap item will be 0, to indicate the end of string */
답변2
항목을 배열로 푸시하고 배열 교체를 사용할 수 있습니다. 이는 요소가 없는 배열을 완전히 최적화할 수 있다는 놀라운 이점을 가지고 있습니다. 다음은 사용자 코드의 수정된 부분입니다.
(
cd "$(dirname "$BASH_SOURCE")"
docker build --build-arg commit_id -t "test-$commit_id" .
set --
test -n "$ti_arg" && set -- "$ti_arg"
docker run "$@" --rm "test-$commit_id"
)
사용하는 경우 사용을 피하고 더 단순화 bash
할 수 있습니다.$@
(
cd "${BASH_SOURCE%/*}"
docker build --build-arg commit_id -t "test-$commit_id" .
args=()
[[ -n "$ti_arg" ]] && args+=("$ti_arg")
docker run "${args[@]}" --rm "test-$commit_id"
)
두 솔루션 모두 "$ti_arg"
의도하지 않은 쉘 평가를 방지하기 위해 큰따옴표를 사용합니다. 이 특별한 경우 쉘이 보간하거나 평가할 수 있도록 $ti_arg
최종 값을 간단히 인용 해제할 수도 있지만 일반적인 솔루션으로는 변수 또는 해당 컨텍스트(포함 )가 손상될 수 있습니다. 내가 더 많은 것을 선호하는 이유에 대한 예상치 못한 입력 위의 복잡하고 완전한 솔루션.docker run
-ti
IFS
docker run $ti_arg --rm "test-$commit_id"