명령 옵션이 명령 내에서 실행되는 다른 스크립트를 손상시키지 않도록 방지하는 방법은 무엇입니까?

명령 옵션이 명령 내에서 실행되는 다른 스크립트를 손상시키지 않도록 방지하는 방법은 무엇입니까?

실행 중에 my_script.shscript()를 실행하는 bash 쉘 script()가 있습니다. their_script내 스크립트( my_script.sh)는 다음과 같습니다.

THISDIR=`dirname $(readlink -f $0)`
main() {
    cd $THISDIR
    source their-script
}
main "$@"

their-script변경해서는 안 되는 파일입니다. their-script이런 것이 있습니다:

BDIR="$1"
...
BDIR=`readlink -f "$BDIR"

위의 모든 것이 훌륭하게 작동합니다. 몇 가지 옵션을 추가하고 싶어서 my_script.sh다음과 같이 변경했습니다.

THISDIR=`dirname $(readlink -f $0)`
check_options() {
    while [ "$1" != "" ]; do
        case $1 in
            --username )  shift
                          OPTIONS_USERNAME=$1
                          ;;
            * )           # No more options
                          ;;
        esac
        shift
    done
}

main() {
    check_options
    cd $THISDIR
    source their-script
}
main "$@"

이제 를 실행하면 ./my_script.sh --username example실행 their-script중에 실패합니다.

readlink -f --username

그리고 다음 줄을 뱉어보세요.

readlink: unrecognized option '--username'

이런 식으로 스크립트의 위치 매개변수가 다른 스크립트를 손상시키는 것을 방지하려면 어떻게 해야 합니까?

답변1

@roaima가 지적했듯이 별도의 프로세스에서 스크립트를 실행하고 싶을 수도 있습니다. 내부 작동 방식을 완전히 이해하지 않고 코드에 포함시키는 것은 매우 위험할 수 있습니다.

FILE_TO_REMOVE="/tmp/foobar"
source some-cool-script
rm -Rf "$FILE_TO_REMOVE"

분명히 이것은 멋진 스크립트에 다음이 포함될 수 있으므로 올바른 방법이 아닙니다.

FILE_TO_REMOVE=/

스크립트가 언제든지 변경될 수 있다는 점은 말할 것도 없습니다("적극적으로" 유지 관리되지 않더라도).

이 외에도 다음 사항도 고려해야 합니다.

  1. 위치 인수 처리는 나머지 인수 수에 따라 더 잘 제어될 수 있습니다.

    while [ $# -gt 0 ]; then
    ...
    done
    

    ""구분 기호로 사용하려는 경우가 아니면 빈 문자열 like는 완벽하게 유효한 인수가 될 수 있습니다. 이렇게 하더라도(전통적으로 --사용됨) 위의 조건을 유지하고 다음을 사용하는 것이 더 나을 수도 있습니다.

        case "$1" in
            ...
            "")
                shift
                break
                ;;
            ...
        esac
    

    이는 유지 관리가 더 쉽습니다.

  2. $@변수는 범위별로 적용됩니다. 즉, 평소와 같이 외부 스크립트를 실행하기로 결정한 경우(예: 코드로 가져오는 대신 호출하여) 매개변수를 전달해야 합니다.

    their-script "$@"
    

    특히 스크립트가 상승된 권한으로 실행되는 경우 스크립트의 전체 경로를 사용하는 것도 나쁘지 않은 생각일 수 있습니다.

  3. 위의 내용은 실제로 명령줄 인수를 확인하지 않는다는 의미이기도 합니다.

    main() {
        check_options
    }
    main "$@"
    

    전화해 주셔야 해요

        check_options "$@"
    
  4. 그러나 위의 내용은 의 매개변수가 main어떤 방식으로도 수정되지 않음 을 의미합니다 check_options. 특정 옵션을 필터링하여 외부 스크립트가 충돌하지 않도록(그리고 질문이 주어지는 경우) 다음 두 가지 옵션이 있습니다.

    • 옵션 해결을 main스크립트의 전역 범위에 넣습니다. 코드 청결성 측면에서 보면 더 빠르고 조금 더 지저분합니다.

    • 별도의 함수에서 옵션 구문 분석을 유지하고 일부 변수 처리를 수행합니다.

      check_options {
          # parse options magic
          # what needs to be passed over is
          # kept in a separate variable
          PASS_THROUGH_OPTS=...
      }
      
      main {
          check_options "$@"
          set -- $PASS_THROUGH_OPTS
          ...
      }
      

      이는 위치 매개변수에 공백이나 다른 단어 구분 기호가 포함될 수 있는 가능성을 처리하지 않는다는 점에 유의하세요. 배열(구현에 따라 다름)을 사용하는 것 외에 이를 올바르게 처리하는 다른 방법은 없으며 다음이 포함됩니다.

      check_options {
          ...
              # parameter should be kept for further use
              x=( "${x[@]}" "$1" )
          ...
      }
      
      check_options "$@"
      set -- "${x[@]}"
      

답변2

이 명령은 쉘이 source their-script스크립트 컨텍스트에서 직접 실행하도록 지시합니다. their-script즉, 모든 변수에 액세스할 수 있고 변경할 수도 있다는 의미입니다.

해당 단어를 제거 source하고 their-script명령으로 실행하면 코드에 영향을 미칠 수 없으며 $1제공하는 첫 번째 인수가 되므로 이 경우 $1다음 값을 사용합니다 banana.

their-script banana

관련 정보