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
user1263746
fonte
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).

huelbois
fonte
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.

wieczorek1990
fonte
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//\"}"
Steven Penny
fonte
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 .

user1587520
fonte
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\
Algum cara programador
fonte
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 ;-))

Dr.Kameleon
fonte
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
killjoy
fonte
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
Jonathan Lin
fonte
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.

Hiro.Protagonist
fonte
comprimentos negativos suportados no bash v4.2
mr.spuratic
8

Esta é a maneira mais discreta sem usar o sed:

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

Ou

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

Resultado:

   quotes: "fish"
no quotes:  fish

Eu recebi isso de uma fonte .

nimig18
fonte
Isso removerá aspas de dentro da string e também das que a rodeiam.
precisa saber é
Além do comentário, isso é idêntico à resposta de StevenPenny de 2012 .
Tripleee 07/10
3

Existe outra maneira de fazer isso. Gostar:

echo ${opt:1:-1}
DevilTour
fonte
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
Gene Pavlovsky
fonte
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'
user1751825
fonte