在Bash中提取两个引号之间的字符串

17

我有一个例子字符串,像这样:Test "checkin_resumestorevisit - Online_V2.mt" Run

我想在bash中提取两个引号之间的文本。我尝试使用以下命令:

SUBSTRING=${echo $SUBSTRING| cut -d'"' -f 1 }

但是它会出现error: bad substitution错误。


1
“坏的替换”是因为您使用了${}而不是$() - Charles Duffy
1
顺便提一下,全大写的变量名是被保留的 -- 请参考 http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html 的第四段,需要注意的是环境变量和 shell 变量共享一个命名空间 -- 建议使用小写名称来命名您自己的变量,以避免与具有系统意义的变量产生意外冲突。 - Charles Duffy
1
此外,在在这里提问之前,请养成通过 http://shellcheck.net/ 运行代码的习惯(它也会指出缺少引号是错误源)。 - Charles Duffy
3个回答

30
为了提取引号之间的子字符串,您可以使用以下其中一种替代方法:

替代方法1:

SUBSTRING=`echo "$SUBSTRING" | cut -d'"' -f 2`

备选方案2:

SUBSTRING=`echo "$SUBSTRING" | awk -F'"' '{print $2}'`

方案三:

set -f;IFS='"'; SUBSTRING=($SUBSTRING); SUBSTRING=${SUBSTRING[1]};set +f

关于问题 #3,如果 SUBSTRING='*"foo"' 并且这段代码在非空目录中运行,请看看它会做什么。更安全的方法是使用 read 在 IFS 上分割。 - Charles Duffy
尽管如此,由于前两个没有正确引用“echo”,它们也容易出现全局扩展错误。如果您想避免这些问题,请使用echo "$SUBSTRING" | ... - Charles Duffy
谢谢@Charles,你说得完全正确!我根据你的建议修复了替代方案。特别是替代方案3是一个可怕的解决方法,但现在应该可以工作了! - Arton Dorneles

5

如果您想提取第一个 " 和最后一个 " 之间的内容:

s='Test "checkin_resumestorevisit - Online_V2.mt" Run'
s=${s#*'"'}; s=${s%'"'*}
echo "$s"

0

其他让@arton-dorneles不再孤单的奇怪想法 :^)

但我最喜欢的是@charles-duffy的回答。

[[ "$SUBSTRING" =~ \"(.*)\" ]] && SUBSTRING="${BASH_REMATCH[1]}"

IFS=\" read -r _ SUBSTRING _ <<<"$SUBSTRING"

# bonus, match either ' or " by pair
SUBSTRING=$(echo "$SUBSTRING" | sed -r "s/.*?([\"'])(.*)\1.*/\2/")

请注意,Bash 为“here string”(<<<)创建一个临时文件,就像为 here documents 一样。

编辑

我花了太长时间才完全理解 Charles Duffy 的批评意见;对于读者来说,这可能是:
SUBSTRING='*"inside text" outside text'

在这种情况下,以下操作是不安全的,因为星号会被展开,列出文件并移动所需结果的索引:
IFS=\" eval '_=($SUBSTRING);SUBSTRING="${_[1]}"'

IFS=\" read -ra _ <<<"$SUBSTRING";SUBSTRING=${_[1]}

这里的第二个选项并没有防止通配符扩展;考虑在至少有两个文件的目录中使用 *"foo" 会发生什么。话虽如此,我肯定喜欢使用 read 方法 -- 如果修复或删除中间错误的建议,它将获得我的赞同。 - Charles Duffy
它确实对我扩展了 *。你怎么期望代码避免这个问题? - Charles Duffy
如果你执行了 touch 'foo ' 'bar ' baz,那么你在上面的评论中的例子将显示 globbing -- 在 IFS 中没有空格,所以第一个双引号前的空格被视为字面量,因此当要匹配的唯一项是 foobarbaz(名称中没有空格)时,glob 找不到匹配项。 - Charles Duffy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接