빈 매개변수를 명령에 전달하는 방법

빈 매개변수를 명령에 전달하는 방법

그래서 나는 이것을 가지고 있습니다 :

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설정되지 않은 변수와 빈 문자열로 설정되는 것의 차이점은 다음과 같습니다.

  1. char *var = NULL; /* unset case. var is 4 or 8 bytes all of which are 0 */
  2. 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-tiIFS

docker run $ti_arg --rm "test-$commit_id"

관련 정보