Shell script: rimuove la prima e l'ultima virgoletta (") da una variabile


225

Di seguito è riportato il frammento di uno script shell da uno script più grande. Rimuove le virgolette dalla stringa trattenuta da una variabile. Lo sto facendo usando sed, ma è efficiente? In caso contrario, qual è il modo efficace?

#!/bin/sh

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

Suggerirei di usare sed "s/^\(\"\)\(.*\)\1\$/\2/g" <<<"$opt". Questa sintassi rimuoverà qoutes solo quando è presente una coppia corrispondente.
John Smith,

@JohnSmith Devo anche sfuggire automaticamente alle virgolette in uno script di shell, ma devo farlo sia che corrispondano o meno, quindi probabilmente non userò quell'espressione che hai postato.
Pysis,

Se hai trovato questa domanda mentre desideri semplicemente rimuovere tutte le virgolette, vedi questa risposta: askubuntu.com/a/979964/103498 .
Gordon Bean,

Risposte:


268

Esiste un modo più semplice ed efficiente, utilizzando la funzione di rimozione prefisso / suffisso della shell nativa:

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

${opt%\"}rimuoverà il suffisso "(scappato con una barra rovesciata per impedire l'interpretazione della shell).

${temp#\"}rimuoverà il prefisso "(scappato con una barra rovesciata per impedire l'interpretazione della shell).

Un altro vantaggio è che rimuoverà le virgolette circostanti solo se ci sono virgolette circostanti.

A proposito, la tua soluzione rimuove sempre il primo e l'ultimo carattere, qualunque essi siano (ovviamente, sono sicuro che conosci i tuoi dati, ma è sempre meglio essere sicuri di ciò che stai rimuovendo).

Usando sed:

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

(Versione migliorata, come indicato da jfgagne, eliminando l'eco)

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

Quindi sostituisce un leader "con niente e un finale anche "con niente. Nella stessa invocazione (non è necessario reindirizzare e avviare un altro file sed. L'utilizzo -epuò avere l'elaborazione di più testi).


14
È possibile eliminare il tubo nella soluzione sed con sed -e 's/^"//' -e 's/"$//' <<< $opt.
jfg956,

1
Ciò potrebbe comportarsi in modo errato se la stringa non ha sia un carattere di virgoletta iniziale che finale. Qualche suggerimento per gestirlo con garbo?
jsears,

Per gestire solo le virgolette esterne corrispondenti, vedere la risposta di @Joachim Pileborg
jsears,

1
@jsears Huh? Questo lo taglia in modo specifico dall'inizio se ce n'è uno e uno alla fine se ce n'è uno. Se non si desidera rimuovere a meno che non siano presenti entrambi; sì, si sedpotrebbe usare un solo regex o la sostituzione della variabile potrebbe essere racchiusa in qualcosa di case $opt in '"'*'"') ... do it ... ;; esac
simile

2
È possibile evitare le espressioni multiple usandosed 's/^"\|"$//g'
tzrlk il

287

Usa tr per cancellare ":

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

Nota : questo rimuove tutte le doppie virgolette, non solo iniziali e finali.


16
Questo non è ciò che OP ha richiesto poiché rimuove anche tutte le virgolette, non solo quelle iniziali e finali.
Lenar Hoyt,

19
Sebbene non risponda esplicitamente a OP, questo mi risolve perché ci sono solo doppie virgolette all'inizio e alla fine di "/ percorso / nome-file". Non ci sono doppie virgolette incorporate. +1
WinEunuuchs2Unix

6
Questa soluzione sarà ciò che molte persone vogliono. In molti casi, gli script possono facilmente ottenere i dati realizzabili in una stringa racchiusa tra virgolette.
Shadoninja,

2
Elegante e mi ha salvato da molto più tempo di debug di errore di prova. Grazie.
Scott Wade,

Questo è ciò che idealmente si desidera ed è per questo che ha più voti della risposta accettata.
apurvc,

38

Questo rimuoverà tutte le doppie virgolette.

echo "${opt//\"}"

1
Ma romperà tra virgolette sfuggite, ad es Don't remove this \" quote. :-(
gniourf_gniourf,

Questa è un'estensione di Bash, quindi non applicabile per lo script di shell in generale. (La domanda è ambigua se questo è importante o meno. I visitatori che lo trovano su Google potrebbero essere alla ricerca di una soluzione POSIX.)
tripleee

Perfezione! Esattamente quello di cui avevo bisogno. Adoro domande come questa che ti danno una miriade di risposte, non solo ciò che OP ha richiesto. Le gemme sono nelle risposte non accettate!
dlite922,

Temo che OP voglia qualcosa che rimuova solo le virgolette iniziali / finali e mantenga quelle sfuggite.
Fernando Paz,

36

C'è un modo semplice usando xargs :

> echo '"quoted"' | xargs
quoted

xargs usa echo come comando predefinito se non viene fornito alcun comando e rimuove le virgolette dall'input. Vedi ad esempio qui .


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

1
Funziona, ma solo per un numero pari di virgolette in una stringa. Se c'è un numero dispari, genera un errore.
James Shewey,


19

Il modo più breve per provare: prova:

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

In realtà rimuove tutte le "s (virgolette doppie) da opt(ci saranno davvero altre doppie virgolette se non all'inizio e alla fine? Quindi in realtà è la stessa cosa e molto più breve ;-))


4
Se vuoi rimuovere tutte le doppie virgolette, allora è ancora meglio usare: "$ {opt // \" /} ". Nessuna pipe, nessuna subshell ... E attenzione che se hai spazi in opt, potresti perdere
Cita

Bene, la variabile legge fondamentalmente il percorso di DocumentRoot dal file di configurazione di httpd, quindi non credo che potrebbe esserci un caso in cui un carattere di citazione potrebbe essere lì nella stringa. E questa sed è molto più ordinata ed efficiente .... Grazie!
user1263746

16

Se stai usando jq e stai provando a rimuovere le virgolette dal risultato, le altre risposte funzioneranno, ma c'è un modo migliore. Utilizzando l' -ropzione, è possibile generare il risultato senza virgolette.

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

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

Sto usando, jqma per favore nota che non funziona se jq sta emettendo anche output ASCII con -a(è un bug al fianco di jq)
Can Poyrazoğlu

yqha anche l' -ropzione:yq -r '.foo' file.yml
Hlib Babii

12

Aggiornare

Una risposta semplice ed elegante da Strippare virgolette singole e doppie in una stringa usando solo i comandi bash / standard Linux :

BAR=$(eval echo $BAR) togli le citazioni da BAR .

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

Sulla base della risposta di hueybois, ho trovato questa funzione dopo molte prove ed errori:

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

Se non si desidera stampare nulla, è possibile convogliare gli eval /dev/null 2>&1 .

Uso:

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

1
Anche se mi piace molto il semplice ed elegante, penso che valga la pena notare che eval non fa solo doppie ritagli di virgolette, ma in realtà valuta come una riga di codice. Pertanto questa tecnica può produrre risultati imprevisti quando BAR contiene altre sequenze che possono sostituire la shell (ad es. BAR = \ 'abc \' o BAR = ab \ 'c o BAR = a \ $ b, o BAR = a \ $ (ls *))
MaxP

11

La soluzione più semplice in Bash:

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

Questo si chiama espansione della sottostringa (vedere il Manuale di Gnu Bash e cercare ${parameter:offset:length}). In questo esempio, la sottostringa prende a spartire dalla posizione 1 e termina alla seconda ultima posizione. Ciò è dovuto al fatto che se lengthè un valore negativo, viene interpretato come un offset di marcia indietro alla fine di parameter.


lunghezze negative supportate da bash v4.2
mr.spuratic l'

8

Questo è il modo più discreto senza usare sed:

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

O

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

Produzione:

   quotes: "fish"
no quotes:  fish

L'ho preso da una fonte .


Questo rimuoverà le virgolette all'interno della stringa e quelle che la circondano.
jsears,

A parte il commento, questo è identico alla risposta di @ StevenPenny del 2012 .
Tripleee


2

La mia versione

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
}

La funzione accetta nomi di variabili e rimuove le virgolette. Elimina solo una coppia di virgolette iniziali e finali corrispondenti. Non controlla se la citazione finale è sfuggita (preceduta da\ quale non è sfuggita essa stessa).

Nella mia esperienza, le funzioni di utilità di stringa per scopi generici come questa (ne ho una libreria) sono più efficienti quando si manipolano direttamente le stringhe, non si utilizza alcun pattern matching e soprattutto non si creano sub-shell o si chiamano strumenti esterni come sed, awko 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

So che questa è una domanda molto antica, ma ecco un'altra variante di sed, che può essere utile a qualcuno. A differenza di alcuni degli altri, sostituisce solo le virgolette all'inizio o alla fine ...

echo "$opt" | sed -r 's/^"|"$//g'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.