Script de shell - remova a primeira e a última cotação (") de uma variável


225

Abaixo está o trecho de um script de shell de um script maior. Ele remove as aspas da string mantida por uma variável. Estou fazendo isso usando sed, mas é eficiente? Caso contrário, qual é a maneira mais eficiente?

#!/bin/sh

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

Eu sugeriria usar sed "s/^\(\"\)\(.*\)\1\$/\2/g" <<<"$opt". Essa sintaxe removerá qoutes somente quando houver um par correspondente.
John Smith

@JohnSmith Eu também tenho que escapar automaticamente de aspas em um script de shell, mas preciso fazê-lo, seja elas correspondentes ou não, por isso provavelmente não utilizarei a expressão que você postou.
Pysis

Se você encontrou esta pergunta enquanto simplesmente deseja remover todas as aspas, consulte esta resposta: askubuntu.com/a/979964/103498 .
Gordon Bean

Respostas:


268

Existe uma maneira mais simples e eficiente de usar o recurso de remoção de prefixo / sufixo nativo do shell:

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

${opt%\"}removerá o sufixo "(escapou com uma barra invertida para impedir a interpretação do shell).

${temp#\"}removerá o prefixo "(escapou com uma barra invertida para impedir a interpretação do shell).

Outra vantagem é que ele removerá as aspas circundantes apenas se houver aspas circundantes.

BTW, sua solução sempre remove o primeiro e o último caractere, sejam eles quais forem (é claro, tenho certeza de que você conhece seus dados, mas é sempre melhor ter certeza do que está removendo).

Usando sed:

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

(Versão melhorada, conforme indicado por jfgagne, eliminando o eco)

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

Portanto, substitui uma liderança "por nada e uma trilha "por nada também. Na mesma chamada (não há necessidade de canalizar e iniciar outro sed. Usando -evocê pode ter vários processos de texto).


14
Você pode se livrar do tubo na solução sed com sed -e 's/^"//' -e 's/"$//' <<< $opt.
jfg956

1
Isso pode se comportar mal, pois a string não possui um caractere de citação à esquerda e à direita. Alguma sugestão para lidar com isso graciosamente?
precisa saber é o seguinte

Para lidar com citações exteriores única correspondência, ver a resposta por @Joachim Pileborg
jsears

1
@jsears Huh? Isso apara especificamente um desde o início, se houver, e um do final, se houver. Se você não deseja remover, a menos que ambos estejam presentes; sim, um únicosed regex poderia ser usado, ou a substituição de variáveis poderia ser envolvido em algo linhacase $opt in '"'*'"') ... do it ... ;; esac
tripleee

2
Você pode evitar as múltiplas expressões usandosed 's/^"\|"$//g'
tzrlk

287

Use tr para excluir ":

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

Nota : Isso remove todas as aspas duplas, não apenas iniciais e finais.


16
Não é isso que o OP solicitou, pois também remove todas as cotações, não apenas as iniciais e as finais.
Lenar Hoyt

19
Apesar de não responder explicitamente ao OP, isso resolve para mim, porque existem apenas aspas duplas no início e no final de "/ path / file-name". Não há aspas duplas incorporadas. 1
WinEunuuchs2Unix 19/02

6
Esta solução será o que muitas pessoas querem. Em muitos casos, o script pode facilmente baixar os dados viáveis ​​para uma cadeia de caracteres entre aspas.
Shadoninja

2
Elegante e me salvou de muito mais tempo de tentativa-erro-depuração. THX.
Scott Wade

É isso que idealmente se quer e é por isso que ela tem mais votos do que a resposta aceita.
apurvc

38

Isso removerá todas as aspas duplas.

echo "${opt//\"}"

1
Mas vai quebrar com aspas escapadas, por exemplo Don't remove this \" quote,. :-(
gniourf_gniourf

Esta é uma extensão do Bash, portanto não aplicável ao shell script em geral. (A questão é ambígua sobre se este é ou não importante Os visitantes que encontrar isso no Google pode estar procurando uma solução POSIX..)
tripleee

Perfeição! Exatamente o que eu precisava. Adoro perguntas como essa que oferecem uma infinidade de respostas, não apenas o que o OP solicitou. As jóias estão nas respostas inaceitáveis!
precisa saber é o seguinte

Receio que o OP queira algo que remova apenas as aspas iniciais e finais e mantenha as que escaparam.
Fernando Paz

36

Existe uma maneira direta de usar xargs :

> echo '"quoted"' | xargs
quoted

O xargs usa eco como o comando padrão se nenhum comando for fornecido e retira aspas da entrada. Veja, por exemplo, aqui .


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

1
Isso funciona, mas apenas para um número par de aspas em uma sequência. Se houver um número ímpar, ele gera um erro.
James Shewey

21

Você pode fazer isso com apenas uma chamada para sed:

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

19

O caminho mais curto - tente:

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

Na verdade, ele remove todos os "s (aspas duplas) de opt(haverá realmente mais aspas duplas além do começo e do fim? Então é a mesma coisa e muito mais breve ;-))


4
Se você deseja remover todas as aspas duplas, é ainda melhor usar: "$ {opt // \" /} ". Sem canal, sem subcamação ... E cuidado, se você tiver espaços em opt, poderá perder .-los Sempre variáveis citação como: echo "$ opt"
huelbois

Bem, a variável basicamente lê o caminho do DocumentRoot a partir do arquivo de configuração do httpd, então não acho que possa haver um caso em que um caractere de citação possa estar lá na string. E esse sed é muito mais limpo e eficiente .... Obrigado!
user1263746

16

Se você estiver usando jq e tentando remover as aspas do resultado, as outras respostas funcionarão, mas há uma maneira melhor. Usando a -ropção, você pode gerar o resultado sem aspas.

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

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

Estou usando, jqmas observe que ele não funciona se o jq também estiver produzindo saída ASCII com -a(é um bug no lado do jq)
Can Poyrazoğlu

yqtambém tem -ropção:yq -r '.foo' file.yml
Hlib Babii

12

Atualizar

Uma resposta simples e elegante de Retirando aspas simples e duplas em uma string usando apenas comandos bash / padrão do Linux :

BAR=$(eval echo $BAR)tiras citações de BAR.

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

Com base na resposta de hueybois, criei essa função após muitas tentativas e erros:

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

Se você não quiser imprimir nada, pode canalizar os resultados /dev/null 2>&1.

Uso:

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

1
Embora eu realmente goste do simples e elegante, acho que vale a pena notar que o eval não faz apenas aparamentos de aspas duplas, mas na verdade é avaliado como uma linha de código. Portanto, essa técnica pode produzir resultados inesperados quando BAR contém outras seqüências que podem ser substituídas pelo shell (por exemplo, BAR = \ 'abc \' ou BAR = ab \ 'c ou BAR = a \ $ b ou BAR = a \ $ (ls *))
MaxP 6/11

11

A solução mais fácil no Bash:

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

Isso é chamado de expansão de substring (consulte o Manual do Gnu Bash e procure ${parameter:offset:length}). Neste exemplo, a substring sinicia na posição 1 e termina na segunda última posição. Isso se deve ao fato de que se lengthfor um valor negativo, ele é interpretado como um deslocamento para trás do final de parameter.


comprimentos negativos suportados no bash v4.2
mr.spuratic


3

Existe outra maneira de fazer isso. Gostar:

echo ${opt:1:-1}

2

Minha versão

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
}

A função aceita nomes de variáveis ​​e retira aspas no lugar. Ele retira apenas um par correspondente de citações iniciais e finais. Ele não verifica se a citação à direita foi escapada (precedida por\ qual não é escapada).

Na minha experiência, funções utilitárias para cadeias de uso geral como esta (eu tenho uma biblioteca delas) são mais eficientes ao manipular as cadeias diretamente, sem usar nenhuma correspondência de padrões e, principalmente, sem criar subconchas ou chamar ferramentas externas, como sed, awkou grep.

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

Eu sei que esta é uma pergunta muito antiga, mas aqui está outra variação sed, que pode ser útil para alguém. Ao contrário de alguns outros, ele substitui apenas aspas duplas no início ou no final ...

echo "$opt" | sed -r 's/^"|"$//g'
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.