如何防止命令选项破坏命令中执行的其他脚本?

如何防止命令选项破坏命令中执行的其他脚本?

我有一个 bash shell script( ),它在执行期间my_script.sh运行 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 exampletheir-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

该命令告诉您的 shell直接在脚本的上下文中source their-script执行。their-script这意味着它可以访问您的所有变量,甚至可以更改它们。

如果您删除该单词source并仅their-script作为命令运行,它将无法影响您的任何代码,并且它将$1是您提供的第一个参数,因此在本例中它将$1采用以下值banana

their-script banana

相关内容