Shell脚本 - 从变量中删除首尾引号(“”)

453

下面是一个脚本的片段,它从一个更大的脚本中提取。 它从一个变量中删除字符串中的引号。 我使用sed来实现它,但它有效吗? 如果不是,那么什么是更有效的方法?

#!/bin/sh

opt="\"html\\test\\\""
temp=`echo $opt | sed 's/.\(.*\)/\1/' | sed 's/\(.*\)./\1/'`
echo $temp

我建议使用 sed "s/^\(\"\)\(.*\)\1\$/\2/g" <<<"$opt"。这个语法只会在有匹配的引号时才移除引号。 - John Smith
@JohnSmith 我也需要在shell脚本中自动转义引号,但我需要无论它们是否匹配都这样做,所以我可能不会使用你发布的那个表达式。 - Pysis
如果您只是想删除所有引号并发现了这个问题,请参考此答案:https://askubuntu.com/a/979964/103498。 - Gordon Bean
19个回答

560
使用 tr 命令删除 "
 echo "$opt" | tr -d '"'

注意:这并没有完全回答问题,会移除所有的双引号,而不仅仅是前后的。请看下面的其他答案。


30
这并不是OP所要求的,因为它同时删除了所有引用,而不仅仅是前导和尾随的引用。 - Lenar Hoyt
36
虽然没有直接回答 OP 的问题,但这对我很有帮助,因为 "/path/file-name" 只有开头和结尾处有双引号,没有嵌套的双引号。+1 - WinEunuuchs2Unix
14
这个解决方案是很多人想要的。在许多情况下,脚本编写可以轻松地将可行数据转换为被引号包围的字符串。 - Shadoninja
5
优雅并且节省了我大量的试错调试时间。谢谢。 - Scott Wade
1
这正是理想的情况,这也是为什么它比被接受的答案获得更多的投票。 - apurvc
显示剩余2条评论

406

有一种更简单、更高效的方法,使用本地 shell 前缀/后缀删除功能:

temp="${opt%\"}"
temp="${temp#\"}"
echo "$temp"

${opt%\"}会删除后缀"(通过反斜杠转义以防止Shell解释)。

${temp#\"}会删除前缀"(通过反斜杠转义以防止Shell解释)。

另一个优点是仅在有周围引号的情况下才会删除周围的引号。

顺便说一句,你的解决方案总是移除第一个和最后一个字符,无论它们是什么(当然,我相信你知道你的数据,但确保您要删除的内容总是更好的)。

使用sed:

echo "$opt" | sed -e 's/^"//' -e 's/"$//'

(根据jfgagne的建议进行改进,去除echo)

sed -e 's/^"//' -e 's/"$//' <<<"$opt"
所以它将一个前导的"替换为空白,也会将尾随的"替换为空白。在同一次调用中(不需要使用管道或启动另一个sed。使用-e可以进行多个文本处理)。

17
使用 sed -e 's/^"//' -e 's/"$//' <<< $opt 命令可以去掉 sed 解决方案中的管道符号。 - jfg956
1
如果字符串没有前导和尾随引号字符,可能会出现错误行为。有没有处理这种情况的优雅方法建议? - jsears
2
@jsears 嗯?这个特别是从开头和结尾各去掉一个。如果你只想在两者都存在时才删除,可以使用单个 sed 正则表达式,或将变量替换包装在类似于 case $opt in '"'*'"') ... do it ... ;; esac 的东西中。 - tripleee
5
通过使用 sed 's/^"\|"$//g',您可以避免多个表达式。 - tzrlk
1
你可以用分号将多个sed表达式连接起来,像这样echo'"foo"'| sed 's/^"//;s/"$//' - Sam
显示剩余7条评论

196

如果你正在使用 jq 并试图从结果中删除引号,其他答案可能有效,但有一种更好的方法。通过使用 -r 选项,您可以输出没有引号的结果。

$ echo '{"foo": "bar"}' | jq '.foo'
"bar"

$ echo '{"foo": "bar"}' | jq -r '.foo'
bar

1
我正在使用 jq,但请注意,如果 jq 也使用 -a 输出 ASCII 输出,则它将无法正常工作(这是 jq 方面的错误)。 - Can Poyrazoğlu
1
yq also has -r option: yq -r '.foo' file.yml - Hlib Babii
echo '{"files":["http://demo.com/1.jpg","http//:demo.com/1.jpg"]}' | jq .files | jq -r 'join(" ")' | xargs wget,当与其他工具一起使用时,-r非常有用。 - chengzi
非常符合我的使用情况,谢谢你的回答! - dingo

93

有一种简单的方法,使用 xargs:

> echo '"quoted"' | xargs
quoted

xargs使用默认命令echo,如果没有提供任何命令并从输入中去掉引号,请参见例如这里。但请注意,这仅在字符串不包含其他引号时才有效。在那种情况下,它将失败(引号数量不匹配)或移除所有引号。


echo '"quoted"' | xargs --> quoted - kyb
3
这个方法可行,但只适用于字符串中引号数为偶数的情况。如果是奇数,就会产生错误。 - James Shewey
2
最简单和最优雅!谢谢。 - rimkashox
2
使用 Terraform 对我很有效。 - rimkashox
2
如果期望值只有开始/结束引号,那么这是最佳解决方案。否则,xargs 将剥离所有引号。 - Metro Smurf
1
这对我来说绝对有效。谢谢。 - Promise Preston

52
如果你是从AWS CLI的--query选项过来的,试试这个--output text选项。

2
准确地说,来自aws cli --query。谢谢! - Gonza
7
对于 Azure CLI,请使用 --output tsv - Eric Herlitz
3
哈哈哈,这正是我想要的。 - Austin Poole
2
我是从AWS CLI过来的,如果你正在使用CLI的输出和jq一起使用,你可以使用-r选项来读取原始字符串。例如:aws codeartifact get-authorization-token --domain ${CODEARTIFACT_DOMAIN} | jq -r '.authorizationToken' - Jose Rodriguez
@JoseRodriguez 我认为最好使用 --query 来完成这个任务。 - Kappacake
显示剩余2条评论

31

你只需要一次调用sed就能完成:

$ echo "\"html\\test\\\"" | sed 's/^"\(.*\)"$/\1/'
html\test\

31

Bash中最简单的解决方案:

$ s='"abc"'
$ echo $s
"abc"
$ echo "${s:1:-1}"
abc
这被称为子字符串扩展(请参见Gnu Bash手册,搜索${parameter:offset:length})。在此示例中,它从位置1开始获取字符串s并在倒数第二个位置结束。这是因为如果length是负值,则将其解释为从parameter的末尾向后运行的偏移量。

1
从bash v4.2开始支持负长度。 - mr.spuratic
1
这不是一个解决方案,因为它会不加选择地移除第一个和最后一个字符。它并不会移除第一个和最后一个引号。 - Cliff

30

最短的路径 - 尝试:

echo $opt | sed "s/\"//g"

这实际上从 opt 中删除了所有的 "(双引号)(除了开头和结尾还会有其他双引号吗?所以实际上是相同的,而且更加简洁;-))


7
如果您想删除所有双引号,那么最好使用:"${opt//"/}"。不需要管道,也不需要子shell……请注意,如果opt中有空格,则可能会丢失它们。始终像这样引用变量:echo "$opt"。 - huelbois
好的,这个变量基本上是从httpd的配置文件中读取DocumentRoot路径,所以我认为在字符串中可能不会出现引号字符的情况。而且这个sed命令更加整洁和高效...谢谢! - user1263746

17

更新

来自于 Stripping single and double quotes in a string using bash / standard Linux commands only 的简单而优美的回答如下:

BAR=$(eval echo $BAR) 可以从 BAR 中去除引号。

=============================================================

在 hueybois 的回答基础上,我经过多次尝试后得出了以下函数:

function stripStartAndEndQuotes {
    cmd="temp=\${$1%\\\"}"
    eval echo $cmd
    temp="${temp#\"}"
    eval echo "$1=$temp"
}
如果您不想打印任何东西,可以将 evals 重定向到 /dev/null 2>&1
用法:
$ BAR="FOO BAR"
$ echo BAR
"FOO BAR"
$ stripStartAndEndQuotes "BAR"
$ echo BAR
FOO BAR

5
虽然我很喜欢简单而优雅的方式,但值得注意的是 eval 并不只是双引号修剪,它实际上会将其作为一行代码进行评估。因此当 BAR 包含其他可能被 shell 替换的序列时(例如 BAR='abc' 或 BAR=ab'c 或 BAR=a$b 或 BAR=a$(ls *)),此技术可能会产生意想不到的结果。 - MaxP

14

我知道这是一个非常老的问题,但这里有另一种sed变体,可能对某些人有用。与其他一些变体不同,它只替换开头或结尾的双引号...

echo "$opt" | sed -r 's/^"|"$//g'

如果您需要匹配单引号或双引号,并且只匹配已经正确引用的字符串。 您可以使用稍微复杂一些的正则表达式...

echo $opt | sed -E "s|^(['\"])(.*)\1$|\2|g"

使用反向引用确保结尾处的引号与开头处相同。


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