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

Posted

技术标签:

【中文标题】Shell 脚本 - 从变量中删除第一个和最后一个引号 (")【英文标题】:Shell script - remove first and last quote (") from a variable 【发布时间】:2012-04-01 18:20:32 【问题描述】:

下面是一个较大脚本的 shell 脚本的 sn-p。它从变量保存的字符串中删除引号。我正在使用 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。 【参考方案1】:

使用tr删除"

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

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

【讨论】:

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

有一种更简单、更有效的方法,使用原生 shell 前缀/后缀去除功能:

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

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

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

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

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

使用 sed:

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

(改进版,如 jfgagne 所示,去掉了回声)

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

因此,它将前导 " 替换为空,而尾随 " 也空替换。在同一个调用中(不需要管道和启动另一个 sed。使用 -e 您可以进行多个文本处理)。

【讨论】:

你可以用sed -e 's/^"//' -e 's/"$//' &lt;&lt;&lt; $opt去掉sed解决方案中的管道。 这可能会使字符串不具有前导和尾随引号字符。有什么优雅的处理建议吗? 要只处理匹配的外引号,请参阅@Joachim Pileborg 的答案 @jsears 嗯?如果有一个,这会从头开始修剪一个,如果有一个,则从结尾修剪一个。如果您不想删除,除非两者都存在;是的,可以使用单个 sed 正则表达式,或者可以将变量替换包装在 case $opt in '"'*'"') ... do it ... ;; esac 行中 你可以使用sed 's/^"\|"$//g'避免多个表达式【参考方案3】:

如果您使用 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【参考方案4】:

有一个简单的方法使用xargs

> echo '"quoted"' | xargs
quoted

xargs 如果没有提供命令,则使用 echo 作为默认命令并从输入中去除引号。参见例如here.

【讨论】:

echo '"quoted"' | xargs --> quoted 这有效,但仅适用于字符串中的偶数个引号。如果有奇数,则会产生错误。 最简单最优雅!谢谢。 为我工作,通过 terraform 使用。【参考方案5】:

最短路径 - 试试:

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

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

【讨论】:

如果你想删除所有的双引号,那么最好使用:"$opt//\"/"。没有管道,没有子外壳......请注意,如果你opt中有空格,你可能会丢失它们。总是引用变量,如:echo "$opt" 嗯,这个变量基本上是从 httpd 的配置文件中读取 DocumentRoot 的路径,所以我不认为字符串中可能存在引号字符的情况。而且这个 sed 更加整洁和高效....谢谢!【参考方案6】:

您只需拨打sed 即可:

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

【讨论】:

【参考方案7】:

Bash 中最简单的解决方案:

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

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

【讨论】:

bash v4.2 支持的负长度【参考方案8】:

更新

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&gt;&amp;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 *) )【参考方案9】:

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

【讨论】:

完全来自 aws cli --query。谢谢! 对于 azure cli 使用 --output tsv 哈哈哈。该死,这正是我想要的【参考方案10】:

这是不使用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相同。【参考方案11】:
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

amzn

【讨论】:

【参考方案12】:

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

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

【讨论】:

【参考方案13】:

在 Bash 中,我会使用以下单行:

[[ "$str" == \"*\" || "$str" == \'*\' ]] && str="$str:1:-1"

这将删除周围的引号(单引号和双引号),同时保持字符串中的引号字符不变。此外,如果只有一个前导引号或只有一个尾随引号,它也不会做任何事情,这通常是我的经验所希望的。

封装在函数中:

#!/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="$*"
echo "Before: $str"
strip_quotes str
echo "After:  $str"

【讨论】:

【参考方案14】:

我的版本

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 var1,2,3,4; do
    echo $i="$!i"
done
strip_quotes var1,2,3,4
echo
echo after:
for i in var1,2,3,4; do
    echo $i="$!i"
done

【讨论】:

【参考方案15】:

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

echo $opt:1:-1

【讨论】:

这个答案有already been given,另一个比较详细。【参考方案16】:

我使用这个正则表达式,它可以避免从没有正确引用的字符串中删除引号:

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/'

输出:>“之前的空格”

【讨论】:

【参考方案17】:

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

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

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

【讨论】:

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

以上是关于Shell 脚本 - 从变量中删除第一个和最后一个引号 (")的主要内容,如果未能解决你的问题,请参考以下文章

如何用shell脚本语言去截取字符串

shell脚本里,如何删除变量的最后一个字符?

从 shell 脚本 (bash) 的参数列表中删除最后一个参数

Shell基础

shell进阶指南

shell进阶指南