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

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

#!/bin/sh


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

你只需要调用sed就可以做到:

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

有一个更简单、更有效的方法,使用本机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你可以有多个文本处理)。

捷径 -尝试:

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

它实际上从opt中删除了所有__abc0(双引号)(除了开头和结尾之外,真的会有更多的双引号吗?所以这实际上是一样的事情,更简短;-))

使用tr删除":

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

注意:这并没有完全回答问题,删除了所有双引号,而不仅仅是开头和结尾。请看下面的其他答案。

这是不使用sed的最离散的方式:

x='"fish"'
printf "   quotes: %s\nno quotes:  %s\n" "$x" "${x//\"/}"

echo $x
echo ${x//\"/}

输出:

   quotes: "fish"
no quotes:  fish

我从一个源得到这个。

我的版本

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

更新

来自仅使用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

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

> echo '"quoted"' | xargs
quoted

如果没有提供命令,xargs使用echo作为默认命令,并从输入中删除引号,参见例:在这里。但是请注意,这只在字符串不包含附加引号的情况下才有效。在这种情况下,它要么失败(引号数量不均匀),要么删除所有引号。

Bash中最简单的解决方案:

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

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

还有另一种方法。如:

echo ${opt:1:-1}

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

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


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

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

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

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

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

这使用了反向引用,以确保结尾的引用与开头相同。

在Bash中,你可以使用下面的一行代码:

[[ "${var}" == \"*\" || "${var}" == \'*\' ]] && var="${var:1:-1}"

这将从存储在var中的字符串中删除周围的引号(单引号和双引号),同时保持字符串中的引号字符完整。同样,如果只有一个前引号或只有一个后引号,或者在开始/结束处有混合引号字符,这将不起任何作用。


包装在函数中:

#!/usr/bin/env bash


# Strip surrounding quotes from string [$1: variable name]
function strip_quotes() {
local -n var="$1"
[[ "${var}" == \"*\" || "${var}" == \'*\' ]] && var="${var:1:-1}"
}


str="'hello world'"
echo "Before: ${str}"
strip_quotes str
echo "After: ${str}"

如果您试图删除引号,因为Makefile保留了它们,请尝试以下方法:

$(subst $\",,$(YOUR_VARIABLE))

基于另一个答案:https://stackoverflow.com/a/10430975/10452175

如果你是从aws cli --query来的,试试这个--output text

Linux=`cat /etc/os-release | grep "ID" | head -1 | awk -F= '{ print $2 }'`


echo $Linux
Output:
"amzn"

从变量中删除双引号的最简单方法是

Linux=`echo "$Linux" | tr -d '"'`
Linux=$(eval echo $Linux)
Linux=`echo ${Linux//\"/}`
Linux=`echo $Linux | xargs`

All提供不带双引号的输出:

echo $ Linux

amazon

我使用这个正则表达式,避免从没有正确引用的字符串中删除引号,这里根据输入显示不同的输出,只有一个开始-结束引号受到影响:

echo '"only first' | sed 's/^"\(.*\)"$/\1/'

输出:>"only first<

echo 'only last"' | sed 's/^"\(.*\)"$/\1/'

输出:>"only last"

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

输出:祝辞both<

echo '"space after" ' | sed 's/^"\(.*\)"$/\1/'

输出:>"空格后quot;& lt;

echo ' "space before"' | sed 's/^"\(.*\)"$/\1/'

输出:在“空间before" & lt;

STR='"0.0.0"' ## OR STR="\"0.0.0\""
echo "${STR//\"/}"
## Output: 0.0.0