Shell脚本-从变量中删除第一引号和最后引号(“)


225

以下是来自较大脚本的Shell脚本的片段。它从由变量保存的字符串中删除引号。我正在使用sed进行操作,但是效率高吗?如果没有,那么有效的方法是什么?

#!/bin/sh

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

我建议使用sed "s/^\(\"\)\(.*\)\1\$/\2/g" <<<"$opt"。仅当存在匹配对时,此语法才会删除qoutes。
约翰·史密斯

@JohnSmith我还必须在shell脚本中自动转义引号,但是无论是否匹配,我都需要这样做,所以我可能不会使用您发布的表达式。
Pysis

如果您只是想删除所有引号而发现了此问题,请参见以下答案:askubuntu.com/a/979964/103498
Gordon Bean

Answers:


268

使用本机外壳程序前缀/后缀删除功能,有一种更简单,更有效的方法:

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

${opt%\"}将删除后缀"(使用反斜杠转义以防止解释外壳)。

${temp#\"}将删除前缀"(使用反斜杠转义以防止解释shell)。

另一个优点是,仅当有引号时才删除引号。

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

使用sed:

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

(改进版本,如jfgagne所示,摆脱了回声)

sed -e 's/^"//' -e 's/"$//' <<<"$opt"

因此,它"用一无所有替换了前导,也没有替换了尾随"。在同一调用中(无需管道传输和启动另一个sed。使用-e该文件可以进行多个文本处理)。


14
您可以使用摆脱sed解决方案中的管道sed -e 's/^"//' -e 's/"$//' <<< $opt
jfg956 2012年

1
这可能会引起误解,因为该字符串没有引号和尾部的引号字符。有什么建议可以优雅地处理吗?
jsears '16

要仅处理匹配的外部引号,请参见@Joachim Pileborg的答案
jsears 2016年

1
@jsears呵呵?具体来说,如果有一个,则从头开始修剪一个,如果有一个,则从头开始修剪一个。如果您不想删除,除非两者都存在;是的,sed可以使用单个正则表达式,也可以将变量替换包装在一行中case $opt in '"'*'"') ... do it ... ;; esac
Tripleee

2
您可以使用sed 's/^"\|"$//g'
tzrlk

287

使用tr删除"

 echo "$opt" | tr -d '"'

注意:这会删除所有双引号,而不仅仅是前导和尾随。


16
这不是OP要求的,因为它还删除了所有引号,而不仅仅是前导和尾随的引号。
Lenar Hoyt 2015年

19
尽管没有明确回答OP,但这为我解决了问题,因为在“ / path / file-name”的开头和结尾都只有双引号。没有嵌入的双引号。+1
WinEunuuchs2Unix

6
这种解决方案将是很多人想要的。在许多情况下,脚本编写可以轻松地将可用数据简化为带引号的字符串。
Shadoninja

2
优雅,使我免于更多的尝试错误调试时间。谢谢。
Scott Wade

理想情况下,这就是人们想要的,这就是为什么它的投票数超过了接受的答案的原因。
apurvc

38

这将删除所有双引号。

echo "${opt//\"}"

1
但是将以转义的引号引起来,例如Don't remove this \" quote:-(
gniourf_gniourf 2012年

这是Bash扩展,因此通常不适用于Shell脚本。(关于这个问题是否重要,这个问题尚不明确。在Google中找到访问者的人可能正在寻找POSIX解决方案。)
Tripleee

完美!正是我需要的。我喜欢这样的问题,这些问题会给您很多答案,而不仅仅是OP的要求。宝石在无法接受的答案中!
dlite922

恐怕OP需要一些仅删除前导/尾随引号并保留转义引号的东西。
费尔南多·帕斯

36

使用xargs有一个简单的方法:

> echo '"quoted"' | xargs
quoted

如果未提供任何命令,xargs将echo作为默认命令使用,并从输入中去除引号。参见例如这里


echo '"quoted"' | xargs -> quoted
kyb

1
这有效,但仅适用于字符串中偶数个引号。如果有一个奇数,它将产生一个错误。
James Shewey


19

最短的解决方法 -尝试:

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

它实际上"从中删除了所有s(双引号)opt(除了在开头和结尾之外,是否还会有其他双引号?所以实际上是同一件事,并且更简短;-))


4
如果要删除所有双引号,则最好使用:“ $ {opt // \” /}“。没有管道,没有子外壳...并且要注意,如果opt中有空格,则可能会松动始终引用变量,例如:echo“ $ opt”
huelbois 2012年

好吧,该变量基本上是从httpd的配置文件中读取DocumentRoot的路径的,所以我认为字符串中可能没有引号字符。而且此sed更加整洁高效。...谢谢!
user1263746'3

16

如果您正在使用jq并尝试从结果中删除引号,则其他答案也可以使用,但是有更好的方法。通过使用该-r选项,您可以输出不带引号的结果。

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

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

我正在使用,jq但请注意,如果jq也输出ASCII输出-a(这是jq侧的一个错误)
无法使用

yq还可以-r选择:yq -r '.foo' file.yml
Hlib Babii

12

更新资料

一个简单而优雅的答案,仅使用bash /标准Linux命令去除字符串中的单引号和双引号

BAR=$(eval echo $BAR)从中删除引号BAR

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

根据hueybois的回答,经过反复试验,我想到了这个功能:

function stripStartAndEndQuotes {
    cmd="temp=\${$1%\\\"}"
    eval echo $cmd
    temp="${temp#\"}"
    eval echo "$1=$temp"
}

如果您不想打印任何内容,则可以将评估传递到/dev/null 2>&1

用法:

$ BAR="FOO BAR"
$ echo BAR
"FOO BAR"
$ stripStartAndEndQuotes "BAR"
$ echo BAR
FOO BAR

1
尽管我真的很喜欢简单而优雅的方法,但是我认为值得注意的是eval不仅会执行双引号修饰,而且实际上是作为一行代码来求值的。因此,当BAR包含可能被外壳替换的其他序列时,例如,BAR = \'abc \'或BAR = ab \'c或BAR = a \ $ b,或BAR = a \ $(ls *))
MaxP

11

Bash中最简单的解决方案:

$ s='"abc"'
$ echo $s
"abc"
$ echo "${s:1:-1}"
abc

这称为子字符串扩展(请参阅Gnu Bash手册并搜索${parameter:offset:length})。在此示例中,它从s位置1开始到第二倒数第二个位置获取子字符串。这是由于以下事实:如果length为负值,则将其解释为相对于末尾的向后偏移parameter


bash v4.2支持负长度
spuratic先生



2

我的版本

strip_quotes() {
    while [[ $# -gt 0 ]]; do
        local value=${!1}
        local len=${#value}
        [[ ${value:0:1} == \" && ${value:$len-1:1} == \" ]] && declare -g $1="${value:1:$len-2}"
        shift
    done
}

该函数接受变量名,并在适当位置删除引号。它仅去除匹配的一对前导和尾随引号。它不检查尾随引号是否被转义(前面\没有被转义的引号)。

以我的经验,像这样的通用字符串实用程序函数(我有它们的库)在直接操作字符串,不使用任何模式匹配,尤其是不创建任何子shell或调用任何外部工具(例如,sedawkgrep

var1="\"test \\ \" end \""
var2=test
var3=\"test
var4=test\"
echo before:
for i in var{1,2,3,4}; do
    echo $i="${!i}"
done
strip_quotes var{1,2,3,4}
echo
echo after:
for i in var{1,2,3,4}; do
    echo $i="${!i}"
done

0

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

echo "$opt" | sed -r 's/^"|"$//g'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.