【问题标题】:Convert a string into an array with bash, honoring quotes for grouping [duplicate]使用 bash 将字符串转换为数组,尊重分组的引号 [重复]
【发布时间】:2016-09-19 05:25:55
【问题描述】:

我有一个字符串:

Str='This string has "a substring"'

字符串有逗号,所以如果我打印我看到的字符串:

echo "${Str}"

This string has "a substring". 

如果我输入命令:

$ Tmp=( ${Str} )
$ echo "${Tmp[3]}"
"a
$ echo "${Tmp[4]}"
Substring"

我想打印:a Substring 有什么建议吗? 我可以更改逗号,但必须将其从 Str 打印到 Tmp

【问题讨论】:

  • 您要考虑哪些字符?假设 Str 包含'a bunch' of `various quotes` with possible "escape \"characters" or mismatched ' quotes, $metachars and $(maybe commands) .?那应该怎么分呢?

标签: bash


【解决方案1】:

如果您已经知道要查找的单词的索引,那么将字符串转换为数组就像使用括号一样简单:

tmp=($(echo $Str))

那么您可以只用 echo ${tmp[4]} ${tmp[5]} 打印不带逗号的“子字符串”。

但是,如果您已经知道子字符串是什么,为什么不从原来的grep 中提取它?

echo $Str | grep -o "a substring"

将以相同的方式返回子字符串,但您无需担心子字符串的长度或数组中单词的索引。

编辑:顺便说一句,如果您只是想删除任何字符串的第一个和最后一个字符,您可以执行(bash 4.2 及更高版本):

echo ${Str:1:-1}

【讨论】:

  • 以数字方式编制索引是不正确的(以一种在语法上尊重字符串的方式进行解析)。
  • 我知道,我只是添加了索引部分以遵循原始问题的行。而且我什至指出这不是最好的方法,而且 grep 的方式更容易处理。
【解决方案2】:

试试这个:

 Str='this string has "a substring"'
 eval Tmp=( "${Str}" )

 printf "%s\n" "${Str}"
 this string has "a substring"

 printf "%s\n" "${Tmp[3]}"
 a substring

 set | grep "^Tmp"
 Tmp=([0]="this" [1]="string" [2]="has" [3]="a substring")

关于eval,我必须警告你,请参阅@charlesduffy 的评论:只有在Str 之前使用你自己的代码行生成时才使用它。

【讨论】:

  • declare -p Tmp 是打印变量定义的更简单的方法,顺便说一句。
  • ...我在这里遇到的问题是,使用eval 意味着您需要相信您的内容不是恶意的(如果攻击者可以控制的任何内容进入您的变量内容,您只需交出了王国的钥匙)。考虑Str='Proxy for greater evil: $(touch /tmp/pwned.txt)' 的行为。
  • @CharlesDuffy 我知道:当使用read 或使用位置参数时,当它与用户提供的数据一起使用时,这很重要。我们也可以想象其他情况。已添加警告。
【解决方案3】:

这个问题需要使用xargs(它把带引号的字符串保留在一起):

$ Str='This string has "a substring"'
$ IFS=$'\n' arr=( $(xargs -n1 <<<"$Str") )
$ printf '<%s>\n' "${arr[@]}"
<This>
<string>
<has>
<a substring>

那么,你需要的元素:

$ echo "${Tmp[3]}"
a substring

请注意,“未引用”项目的前导或尾随空格将被删除:

$ Str='  This    string    has "   a substring  "'
$ IFS=$'\n' arr=( $(xargs -n1 <<<"$Str") )
$ printf '<%s>\n' "${arr[@]}"
<This>
<string>
<has>
<   a substring  >

【讨论】:

  • 我可能会使用 while IFS read -r -d '' item; do arr+=( "$item" ); done &lt; &lt;(xargs printf '%s\0' &lt;&lt;&lt;"$Str") 以允许在项目中使用换行文字。也就是说,AFAICT 这是不使用 Python 的 shlex 模块之类的最佳可用通用答案。
  • @CharlesDuffy 好吧,在引号内包含换行符的字符串:Str=$'string has "a \n substring"' 将失败并显示 xargs:xargs &lt;&lt;&lt;"$Str",并显示以下消息:xargs: unmatched double quote;。 .... 但是,如果换行符在引号之外,它将适用于您的代码。
  • 工作正常,谢谢。你能解释一下为什么-n1 部分吗? XArgs 手册页 (man7.org/linux/man-pages/man1/xargs.1.html) 对我来说不够清楚。
猜你喜欢
  • 1970-01-01
  • 2017-10-02
  • 2021-10-09
  • 2013-12-05
  • 2021-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多