我在将参数传递给Bash脚本中的命令时遇到问题。

poc.sh:

#!/bin/bash

ARGS='"hi there" test'
./swap ${ARGS}

交换:
#!/bin/sh
echo "${2}" "${1}"

当前输出为:
there" "hi

仅更改poc.sh(因为我相信swap可以正确执行我想要的操作),如何使poc.sh传递“hi there”并作为两个参数进行测试,而“hi there”周围没有引号?

最佳答案

几个入门词

如果可能的话,请不要使用用引号引起来的字符串作为输入格式。

  • 很难一致地解析:不同的shell具有不同的扩展名,并且不同的非shell实现实现不同的子集(请参见下面的shlexxargs之间的增量)。
  • 很难以编程方式生成。 ksh和bash具有printf '%q',它将生成一个用shell引用的字符串,该字符串带有任意变量的内容,但是在POSIX sh标准中不存在与此等效的字符串。
  • 不好解析很容易。使用这种格式的许多人都使用eval,它具有相当大的安全性问题。

  • 以NUL分隔的流是一种更好的做法,因为它们可以准确地表示任何可能的shell数组或参数列表,而不会产生任何歧义。

    xargs,带有bashisms

    如果要使用 shell 程序引号从人工生成的输入源获取参数列表,则可以考虑使用xargs对其进行解析。考虑:
    array=( )
    while IFS= read -r -d ''; do
      array+=( "$REPLY" )
    done < <(xargs printf '%s\0' <<<"$ARGS")
    
    swap "${array[@]}"
    

    ...会将解析后的$ARGS内容放入数组array中。如果您想从文件中读取,请用<filename代替<<<"$ARGS"

    xargs,符合POSIX

    如果您试图编写与POSIX sh兼容的代码,这将变得更加棘手。 (为了降低复杂性,我将在此处假设文件输入):
    # This does not work with entries containing literal newlines; you need bash for that.
    run_with_args() {
      while IFS= read -r entry; do
        set -- "$@" "$entry"
      done
      "$@"
    }
    xargs printf '%s\n' <argfile | run_with_args ./swap
    

    这些方法比运行xargs ./swap <argfile更安全,因为如果存在更多或更长的参数(而不是将多余的参数作为单独的命令运行),则会引发错误。

    带有shash的Python shlex-而不是xargs-

    如果您需要比xargs实现更准确的POSIX sh解析,请考虑改用Python shlex模块:
    shlex_split() {
      python -c '
    import shlex, sys
    for item in shlex.split(sys.stdin.read()):
        sys.stdout.write(item + "\0")
    '
    }
    while IFS= read -r -d ''; do
      array+=( "$REPLY" )
    done < <(shlex_split <<<"$ARGS")
    

    关于bash - 从字符串中正确读取带引号/转义的参数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26067249/

    10-11 23:20
    查看更多