【问题标题】:Passing command line parameters in bash, detecting content of parameters在bash中传递命令行参数,检测参数内容
【发布时间】:2014-09-05 01:09:49
【问题描述】:

我正在编写一个 bash 脚本,它将

  1. 根据传递的第一个参数表现不同(目前没有问题)
  2. 将其余参数传递给命令(目前没有问题)
  3. 如果参数包含字符串,则表现不同

看起来像:

[[ "${1}" = "-h" || "${1}" = "--help" ]] && echo -e "somehelp"
[[ "${1}" = "echo" ]] && echo ${*:2}
[[ "${1}" = "emerge" ]] && emerge -uDN ${*:2}
some-magic-here

现在,如果我这样做了

myscript emerge -a whatever whatever2 --option 

它会运行

emerge -uDN -a whatever whatever2 --option

但是,万一“whatever”是一个包含*的字符串,比如

myscript emerge -uDN -a whatever/* whatever2 --option

我希望它运行

emerge -uDN -a $(eix -u --only-names whatever/*) whatever2 --option

相反。有什么建议吗?

【问题讨论】:

  • 这是不可能的,因为 Bash 会在 * 传递给您的脚本之前对其进行扩展。除非你在引号中写"whatever/*"
  • 有可能,您只需引用您的输入。 IE。 myscript emerge -uDN -a 'whatever/*' whatever2 --option 或关闭 globbing。

标签: bash parameter-passing


【解决方案1】:

首先,如果您要将* 传递给脚本,您必须防止命令行中的shell 进行扩展。最简单的方法是引用它:

myscript emerge -a 'whatever/*' whatever2 --option

由于您已经在使用 [[ 运算符,注意: 以下是 仅限 bash 解决方案,不能移植到 sh。要确定 $3 是否包含*,您可以使用=~ 运算符:

[[ "${1}" == "emerge" ]] && {
    [[ "$3" =~ "*" ]] && \
        emerge -uDN $2 $(eix -u --only-names $3) ${*:4} || \
        emerge -uDN ${*:2}
}

如果逻辑有点模糊,您还可以将复合命令重写为嵌套的 if-else 语句。试一试,如果您有任何问题,请告诉我。

【讨论】:

    【解决方案2】:

    你提到了命令行:

    myscript emerge -uDN -a whatever/* whatever2 --option
    

    myscript 在其参数列表中看到* 的唯一方法是如果当前目录下没有子目录whatever,或者它是一个空目录(严格来说:如果它包含任何文件,则名称都以.) 开头,在任何一种情况下,您都没有设置shopt -s nullglob。如果不满足这些条件,调用myscript 的shell 将适当地替换*,而myscript 将看不到*。 (当然,如果你引用参数——"whatever/*"'whatever/*',那么myscript 也将看到* 元字符,而不管nullglob 以及是否存在whatever 子目录。)

    尚不清楚* 是否仅在-a 选项之后才需要替换,或者是否应该在任何参数中替换。我将假设所有论点都需要替换;如果只是 -a 之后的参数应该被替换,那并没有太大的不同。

    没有处理whatever/*的代码,命令看起来像:

    [[ "${1}" = "emerge" ]] && exec emerge -uDN "${@:2}" || exit 1
    

    区别:

    1. exec 是可选的,但保证在emerge 命令之后不会执行任何操作(除非找不到emerge 命令,在这种情况下|| exit 1 确保不会执行任何其他操作)。

    2. 使用"$@" 保留提供给脚本的参数。没有双引号,$@$* 之间没有区别。在双引号内,"$*" 生成单个字符串,但"$@" 生成传递给脚本的每个参数。 "${@:2}" 表示法在第二个到最后一个参数中执行此操作。

    要处理任何参数的*,我们需要检测*。如果我们使用数组,这将是最简单的。

    数组arglist 将包含要传递给emerge 命令的参数。我们需要遍历脚本的参数,检查 * 的出现:

    arglist=( "-uDN" )
    for arg in "${@:2}"
    do
        case "$arg" in
        (*\**) arglist+=( $(eix -u --only-names "$arg") );;
        (*)    arglist+=( "$arg" );;
        esac
    done
    exec emerge "${arglist[@]}"
    exit 1
    

    请注意,这假定eix 将扩展元字符(准确地说是*),而不是依赖shell 来这样做。正如问题所假设的那样,它还假设eix 生成的名称中没有空格。如果有的话,$(…) 符号将在空格(或制表符、或换行符……)处分割名称。

    此代码最好作为then 子句的主体处理

    if [[ "${1}" = "emerge" ]]
    then
        …
    fi
    

    这比试图将所有代码压缩到一行更清楚(可以这样做,但是这样做没有意义,而且很多不这样做)。

    【讨论】:

      【解决方案3】:

      这里有一个线索:

      #!/bin/sh
      
      x="bbbccc"     # Put different strings in here, and see what happens
      
      case "$x" in
      *\**)
          echo "Yes"
          ;;
          *)
          echo "No"
          ;;
      esac
      

      【讨论】:

        猜你喜欢
        • 2014-10-17
        • 2016-03-25
        • 1970-01-01
        • 1970-01-01
        • 2021-11-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-23
        相关资源
        最近更新 更多