如何正确解析 shell 脚本中带引号的 arg-list 字符串?

如何正确解析 shell 脚本中带引号的 arg-list 字符串?
概括

如何将单个字符串转换a "b" 'c d' $'e\nf'为单独的参数,尊重引号并保留空格和换行符?

问题

我正在尝试读取并处理一个脚本的输出,该脚本以引用字符串的形式导出值列表(每行一个)(由 创建printf %q)。列表中的值以空格分隔,可以用引号引起来,可以包含空格和换行符,并且计数未知。

例子:a "b" 'c d' $'e\nf'

我正在寻找一种方法来恢复 POSIX shell 脚本中的值并将它们作为 shell 函数的参数进行处理。

所需的解决方案,按优先级降序排列:

  1. POSIX shell 命令和核心实用程序xargsprintf例如 等;不eval
  2. 重击
  3. 像 perl 这样成熟的编程语言
shell 脚本的骨架process.sh
#!/bin/sh
set -eu

process() {
  printf '>%s<\n' "${@}"
}

main() {
  value_list="${1}"
  # split value list here and set positional parameters
  set -- ???
  process "${@}"
}

main "${@}"
期望的行为
$ process.sh "a \"b\" 'c d' $'e\nf'"
>a<
>b<
>c d<
>e
f<
到目前为止发生了什么
  • 我尝试了printf(包括%q)、xargs循环while read、更改IFS、用字节分隔参数null、子 shell 调用、heredocs 的不同组合。
  • xargs允许取消引用,但仅适用于空格,不适用于换行符,并且仅适用于不带参数的情况-d
  • 循环while read可以解析参数,但不允许在从管道读取输入时调用 shell 函数

答案1

这个答案是基于评论经过伊尔卡丘并使用zsh.

外壳脚本process.sh
#!/bin/sh
set -eu
export script="$(readlink -f "${0}")"

split() {
  zsh -c 'printf "%s\0" "${(Q@)${(z)1}}"' "${script}/split" "${@}"
}

process() {
  printf '>%s<\n' "${@}"
}

main() {
  value_list="${1}"
  split "${value_list}" | xargs -0 sh -c 'init() { . "${script}"; } && init && process "${@}"' "${script}/main"
}

[ "${#}" -eq 0 ] || main "${@}"
好处
  • 有用
缺点
  • 必须获取脚本来调用process()form xargs,将其封装在函数中以去除参数并防止无限循环有点尴尬
  • 要求zsh

答案2

一个简化的变体 zsh基于的答案:

#!/bin/zsh
set -eu

process() {
  printf '>%s<\n' "${@}"
}

main() {
  value_list="${1}"
  process "${(Q@)${(z)value_list}}"
}

main "${@}"
好处
  • 有用
缺点
  • zsh 的要求

相关内容