【问题标题】:In Bash (and other shell languages), how to preserve space escape characters in parameters that get passed through在 Bash(和其他 shell 语言)中,如何在传递的参数中保留空格转义字符
【发布时间】:2019-09-09 15:14:10
【问题描述】:

我有一个脚本,当直接调用它时,可以使用以下参数组合正常工作:

--path=/path/to/a\ folder\ with\ spaces
--path='/path/to/a folder with spaces'
--path="/path/to/a folder with spaces"

但我在将参数从帮助脚本传递给它时遇到了困难。

我已经尝试了很多东西,但在每种情况下,我的脚本都收到以下内容:--path=/path/to/a folder with spaces 这使我的脚本感到困惑,并且好像/path/to/a 是路径(即 --path 的参数)和 @ 987654326@ with spaces 是附加参数。

作为一个最小示例,以下都不会产生所需的结果(将以下内容保存到所需的工作目录中,为 ./so_example.shchmod +x ./so_example.sh):

#!/usr/bin/env bash
set -x

printf "%s\n" "$@"

echo "$@"

echo -e "$@"

printf "%s\n" $@

echo $@

echo -e $@

当以下列方式调用时:

./so_example.sh --path=/path/to/a\ folder\ with\ spaces
./so_example.sh --path='/path/to/a folder with spaces'
./so_example.sh --path="/path/to/a folder with spaces"

我得到以下输出:

+ printf '%s\n' '--path=/path/to/a folder with spaces'
--path=/path/to/a folder with spaces
+ echo '--path=/path/to/a folder with spaces'
--path=/path/to/a folder with spaces
+ echo -e '--path=/path/to/a folder with spaces'
--path=/path/to/a folder with spaces
+ printf '%s\n' --path=/path/to/a folder with spaces
--path=/path/to/a
folder
with
spaces
+ echo --path=/path/to/a folder with spaces
--path=/path/to/a folder with spaces
+ echo -e --path=/path/to/a folder with spaces
--path=/path/to/a folder with spaces

我希望得到以下输出之一以获得正确的解决方案:

--path=/path/to/a\ folder\ with\ spaces`
--path='/path/to/a folder with spaces'`
--path="/path/to/a folder with spaces"`

【问题讨论】:

  • 我确实花了一些时间在 Stackoverflow 上寻找答案。我的搜索词肯定是不充分的,因为直到现在我才找到stackoverflow.com/questions/21820240/…,我认为它描述了我面临的问题。
  • "$@" 两边加上双引号,但您可能会发现"$*" 更合适,请参阅unix.stackexchange.com/questions/41571/…
  • 我确实演示了在问题中使用双引号,但这不起作用。不过,printf "%q\n" "$@" 确实以合适的方式打印出来。我真正的问题一定与此无关,但现在我至少有更好的调试方法。
  • 我不确定问题是什么;如果引用参数扩展,则保留给定值。但是,用于创建值的引用不是。 (因为您的脚本从未看到该字符串;它在调用脚本之前由 调用者 进行评估。)如果您在将此类参数传递给帮助脚本时遇到问题,您可能在应该使用数组的地方使用常规变量。其他语言不存在类似问题,因为它们不依赖参数扩展。
  • 我认为我在脚本的错误区域发现了问题。道歉。我有更好的方法来准确调试内部脚本现在看到的内容。

标签: linux bash shell parameter-passing


【解决方案1】:

您必须在单个处理中显式使用“$1”或迭代“$@”。如果您需要在单个 var 中保留 "$@" 的空格,请使用字符串操作来使用不间断空格进行掩码。

以下示例将使用 --path="PATTERN" 和 --path "PATTERN"。它从 "$@" 中删除所有路径并将其移动到单个 var $paths 中(以防 "$@" 包含您要保留的其他参数)

# remove options from positional parameters and read arguments
i=1
while [ $i -le $# ]
  do
    case "$1" in
      --path=*)
        test -a "$1"
        if [ $? != 0 ]
          then
            # allow nontrivial names in --path=PATTERN
            # (space, tab, newline, linefeed, formfeed, vertical tab)
            paths="${paths} ${1//[[:space:]]/[[:space:]]}"
            i=$(($i-1))
          else
            set -- "$@" "$1"
        fi
      ;;
      --path)
        test -a "$1"
        if [ $? != 0 ]
          then
            # allow nontrivial names in --path PATTERN
            # (space, tab, newline, linefeed, formfeed, vertical tab)
            paths="${paths} $1=${2//[[:space:]]/[[:space:]]}"
            shift
            i=$(($i-1))
          else
            set -- "$@" "$1"
        fi
      ;;
       *)
        set -- "$@" "$1"
      ;;
    esac
    shift
    i=$(($i+1))
done

# you can now pass the arguments to your command. the [[:space:]] will
# recognized as wildcard and will match all names containing spaces
<command> $paths

# however, if you want to display names (or if these paths not exist),
# you can convert it back (only spaces unfortunately)
for path in $paths
  do
    # revert back replacements [[:space:]] -> ' '
    path="${path//\[\[:space:]]/ }"

    # print everything before separator: ${VAR%%=*}
    # print the separator: (=)
    # print double quote: (\")
    # print everything after separator: ${VAR#*=}
    # print double quote: (\")

#    echo -e " ${path%%=*} = \" ${path#*=} \" "
    echo -e "${path%%=*}=\"${path#*=}\""
done

# other arguments are still available in positional parameters
for rest in "$@"
  do
    echo -e $rest
done

【讨论】:

    【解决方案2】:

    问题是您希望将语法引号传递给您的脚本;他们不是。所有三个

    --path=/path/to/a\ folder\ with\ spaces
    --path='/path/to/a folder with spaces'
    --path="/path/to/a folder with spaces"
    

    调用者 评估以产生与参数完全相同的值 (--path=/path/to/a folder with spaces)。在脚本中引用位置参数会保留这些空格,但您的脚本无法知道调用它的人如何创建该值。 (它可能是以您的脚本一无所知的方式创建的;考虑像dash -c 'printf "%s\n" "$1"' _ $'\t' 这样的命令从bash 运行。dash 获取单个制表符作为其参数,但它不会知道任何关于$'...' 语法 bash 用于创建它。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-14
      • 1970-01-01
      • 2019-09-16
      • 1970-01-01
      • 2013-02-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多