ChatGPT解决这个技术问题 Extra ChatGPT

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

下面是一个较大脚本的 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脚本中自动转义引号,但无论它们是否匹配,我都需要这样做,所以我可能不会使用你发布的那个表达式。
如果您只是想删除所有引号时发现此问题,请参阅此答案:askubuntu.com/a/979964/103498

M
Mike Q

使用 tr 删除 "

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

注意:这并不能完全回答问题,会删除所有双引号,而不仅仅是前导和尾随。请参阅下面的其他答案。


这不是 OP 要求的,因为它还删除了所有引号,而不仅仅是前导和尾随的。
虽然没有明确回答 OP,但这对我来说解决了,因为“/path/file-name”的开头和结尾只有双引号。没有嵌入的双引号。 +1
这个解决方案将是很多人想要的。在许多情况下,脚本可以轻松地将可用数据转换为用引号括起来的字符串。
优雅,让我免于更多的试错调试时间。谢谢。
理想情况下,这就是人们想要的,这就是为什么它比接受的答案拥有更多的选票。
Y
Yuri

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


您可以使用 sed -e 's/^"//' -e 's/"$//' <<< $opt 摆脱 sed 解决方案中的管道。
这可能会使字符串不具有前导和尾随引号字符。有什么优雅地处理的建议吗?
@jsears 嗯?如果有一个,这会从头开始修剪一个,如果有一个,则从结尾修剪一个。如果您不想删除,除非两者都存在;是的,可以使用单个 sed 正则表达式,或者变量替换可以包含在行 case $opt in '"'*'"') ... do it ... ;; esac
您可以使用 sed 's/^"\|"$//g' 避免多个表达式
您可以使用分号连接多个 sed 表达式,例如 echo '"foo"' | sed 's/^"//;s/"$//'
k
killjoy

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

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

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

我正在使用 jq 但请注意,如果 jq 还使用 -a 输出 ASCII 输出,则它不起作用(这是 jq 方面的错误)
yq 也有 -r 选项:yq -r '.foo' file.yml
echo '{"files":["http://demo.com/1.jpg","http//:demo.com/1.jpg"]}' | jq .files | jq -r 'join(" ")' | xargs wget , -r 在与其他工具进行管道时非常有用。
u
user1587520

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

> echo '"quoted"' | xargs
quoted

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


echo '"quoted"' | xargs --> quoted
这有效,但仅适用于字符串中的偶数个引号。如果有奇数,则会产生错误。
最简单最优雅!谢谢。
通过 terraform 为我工作。
这是最好的解决方案如果期望值只有开始/结束引号。否则,xargs 将删除所有引号。
P
Peter Mortensen

最短的方法 - 尝试:

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

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


如果你想删除所有的双引号,那么最好使用:“${opt//\”/}”。没有管道,没有子外壳......并且要注意,如果你在 opt 中有空格,你可能会松动总是引用变量,例如: echo "$opt"
好吧,该变量基本上是从 httpd 的配置文件中读取 DocumentRoot 的路径,所以我认为不会有引号字符可能存在于字符串中的情况。而且这个 sed 更加整洁和高效....谢谢!
S
Some programmer dude

您只需一次调用 sed 就可以做到这一点:

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

P
Peter Mortensen

Bash 中最简单的解决方案:

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

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


bash v4.2 支持的负长度
J
Jehong Ahn

如果您来这里是为了 aws cli --query,请尝试 --output text


完全来自 aws cli --query。谢谢!
对于 azure cli,使用 --output tsv
哈哈哈。该死的,这正是我想要的
J
Jonathan Lin

更新

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"
}

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

用法:

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

虽然我真的很喜欢简单和优雅,但我认为值得注意的是 eval 不只是做双引号修剪,而是实际上作为一行代码进行评估。因此,当 BAR 包含可能被 shell 替换的其他序列时(例如 BAR=\'abc\' 或 BAR=ab\'c 或 BAR=a\$b 或 BAR=a\$(ls *) )
P
Peter Mortensen

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

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

或者

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

输出:

   quotes: "fish"
no quotes:  fish

我从 a source 得到这个。


这将删除字符串中的引号以及围绕它的引号。
除了注释之外,这与 @StevenPenny's answer from 2012 相同。
请注意,这使用了特定于 bash 的变量替换,并且在 sh 中不起作用。也就是说,我认为使用 bash 时这是最好的答案。
K
Kiruthika kanagarajan
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 提供不带双引号的输出:

回声 $Linux

亚马逊


u
user1751825

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

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

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

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

这使用反向引用来确保末尾的引用与开头的引用相同。


M
Maxxim

在 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}"

更简单的 1 班轮... echo $opt | sed -E "s|^(['\"])(.*)\1$|\2|g"
@user1751825:OP 的问题是 从变量保存的字符串中删除引号,因此您需要将单行代码更改为 temp=$(echo "$opt" | sed -E "s|^(['\"])(.*)\1$|\2|g") 以实现该结果(另外,不要忘记引用 $opt)。因此,您需要使用 subshell + 管道来 sed。由于 OP 还要求提供 高效 解决方案,因此您的单线解决方案绝不比我的 Bash-only 解决方案更简单或更好。
G
Gene Pavlovsky

我的版本

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

F
Federico Firenze

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

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

输出:>“只有第一个<

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

输出:>“仅最后一个”<

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

输出:>两者<

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

输出:>“后面的空格”<

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

输出:>“之前的空格”<


P
Peter Mortensen

还有另一种方法可以做到这一点。喜欢:

echo ${opt:1:-1}

这个答案有already been given,另一个更详细。
J
James Bond

如果您因为 Makefile 保留引号而尝试删除引号,请尝试以下操作:

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

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


$(subst ...) 是一个 make 函数。 OP没有提到任何Makefile