【问题标题】:How to pass arguments to a script invoked by source command?如何将参数传递给源命令调用的脚本?
【发布时间】:2017-02-07 16:27:19
【问题描述】:

我正在通过source 命令调用脚本并希望将参数传递给脚本。

我检查了man source,bash 返回:

:[参数]
没有效果;该命令除了扩展参数和执行任何指定的重定向之外什么都不做。返回零退出代码。

源文件名[参数]
在当前 shell 环境中从 filename 读取并执行命令,并返回从 filename 执行的最后一个命令的退出状态。如果文件名不包含斜杠,则使用 PATH 中的文件名来查找包含文件名的目录。在 PATH 中搜索的文件不必是可执行文件。当 bash 不是 posix 模式时,如果在 PATH 中没有找到文件,则搜索当前目录。如果关闭 shopt 内置命令的 sourcepath 选项,则不会搜索 PATH。如果提供了任何参数,它们将在执行 filename 时成为位置参数。否则位置参数不变。返回状态是脚本中退出的最后一个命令的状态(如果没有执行任何命令,则返回 0),如果找不到文件名或无法读取文件名,则返回 false。

没有例子,所以没看懂。

【问题讨论】:

    标签: linux bash


    【解决方案1】:

    我偶然发现了另一个陷阱

    test.sh

    echo "I was given $# argument(s):"
    printf "%s\n" "$@"
    source test2.sh
    

    test2.sh

    echo "I was given $# argument(s):"
    printf "%s\n" "$@"
    

    现在打电话

    >bash test.sh a b
    

    输出:

    I was given 2 argument(s):
    a
    b
    I was given 2 argument(s):
    a
    b
    

    如果 test2.sh 分别评估参数,这可能是一个问题。论据计数。为避免这种情况,您可以将 args 移开。

    test.sh

    echo "I was given $# argument(s):"
    printf "%s\n" "$@"
    for arg in "$@"; do shift; done
    source test2.sh
    

    编辑:

    刚刚注意到https://stackoverflow.com/users/4633275/hamlet 已经涵盖了这个主题。

    另见Avoid command line arguments propagation when sourcing bash script

    【讨论】:

      【解决方案2】:

      扩展 redneb 的(当前接受的)答案...

      TL;DR需要在另一个脚本中获取没有位置参数的脚本?试试function DoSource() { source test.sh ; } ; DoSource 而不是source test.sh

      sourceing 在另一个脚本中没有参数的脚本

      问题中 Bash 手册的摘录显示了如何将位置参数分配给源脚本的详细信息。特别是,如果源命令没有指定任何参数,它会被分配来自调用环境的参数。

      结果是source 一个脚本不传递参数 在另一个脚本中可能很麻烦。 例如,让我们使用 redneb 示例为test.sh

      echo "I was given $# argument(s):"
      printf "%s\n" "$@"
      

      来源于另一个脚本userScript.sh,例如单线:

      source test.sh
      

      运行上述示例时:

      $ bash userScript.sh a 'b c'
      I was given 2 argument(s):
      a
      b c
      

      test.sh 继承 userScript.sh 位置参数...现在不是我想要的(如果我这样做了,我可以使用 source test.sh "$@")。

      我发现以下是一个有用的解决方法:将源命令封装到 Bash 函数中。新的userScript.sh 看起来像:

      function DoSource() { source test.sh ; }
      DoSource
      

      报告:

      $ bash userScript.sh a 'b c'
      I was given 0 argument(s):
      
      

      请注意,指定空参数 (source test.sh '') 并不等效,因为空参数将传递给 test.sh

      如果采购脚本也需要采购

      如果userScript.sh 本身应该被采购,那么人们可能不想离开DoSource()。在这种情况下,简单的解决方案是自我毁灭:

      function _userScript_sh_DoSource() { source test.sh ; unset "$FUNCNAME" ; }
      _userScript_sh_DoSource
      

      一次性使用(已选择函数名称以减少名称冲突的机会);或者unset _userScript_sh_DoSource 命令可以放在不再需要_userScript_sh_DoSource 之后。

      多种用途的灵活变体

      DoSource() 的更复杂变体:

      function DoSource() { local ScriptName="$1" ; shift ; source "$ScriptName" ; }
      DoSource test1.sh
      DoSource test1.sh "$@"
      DoSource test2.sh
      

      可以用作source 的“插入式”替代品,唯一的区别是当没有为要获取的脚本指定位置参数时,source 继承它们,而DoSource 不使用. 但请注意,DoSource 是一个函数,因此在其他方面(例如堆栈调用、FUNCNAME、...)的行为与 source 不同。

      【讨论】:

        【解决方案3】:

        Bourne shell 和其他一些 shell 忽略传递给“.”的参数。 (见https://unix.stackexchange.com/questions/5024/passing-variables-to-a-bash-script-when-sourcing-it)。

        我可以提出一种解决方法。假设您要获取的脚本如下所示:

        $ cat ./setEnv 
        export BRANCH=$0
        export TARGET=$1
        

        通常的方式不起作用:

        $ sh -c '. ./setEnv master linux; echo BRANCH=$BRANCH ; echo TARGET=$TARGET'
        BRANCH=sh
        TARGET=
        

        但是,如果您在 ' ' 之后指定参数,那么它们将属于父 shell,即它们可以在您正在采购的脚本中访问:

        $ sh -c '. ./setEnv; echo BRANCH=$BRANCH ; echo TARGET=$TARGET' master linux
        BRANCH=master
        TARGET=linux
        

        当我需要 Bourne shell 中的单行命令时,我会使用这种方式,该命令从“. ./setEnv”开始,并以多个命令分隔,并以 ; 分隔。或 &&。

        【讨论】:

          【解决方案4】:

          创建一个文件test.sh,内容如下:

          echo "I was given $# argument(s):"
          printf "%s\n" "$@"
          

          然后从交互式 shell 会话中获取它:

          $ source ./test.sh a 'b c'
          I was given 2 argument(s):
          a
          b c
          

          因此您可以像在常规 bash 脚本中一样访问参数,使用 $@$1$2$3 等。

          为了比较,将其作为常规脚本运行:

          $ bash ./test.sh a 'b c'
          I was given 2 argument(s):
          a
          b c
          

          【讨论】:

          • script != bash :(。这不适用于 POSIX 兼容的 shell(破折号)。
          • 问题标记为bash;不需要符合 POSIX 标准的答案。
          • 虽然不是必需的,但请注意:我们必须生活在混合 shell 环境中,很高兴知道这不符合 POSIX,而是 BASH(/ZSH/KSH/. ..) 仅限。
          • 这个问题可能被标记为 bash,但对于我们这些需要编写 POSIX shell 脚本的人来说,找到非 bash 的答案已经足够困难了。而且,不幸的是,(最近合理的)bash 并没有那么普遍(参见 MacOS Darwin)。我非常感谢提供 POSIX shell 解决方案。
          猜你喜欢
          • 2013-10-11
          • 1970-01-01
          • 2020-09-19
          • 1970-01-01
          • 2014-03-08
          • 2013-10-22
          • 2016-12-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多