Script de shell: elimina la primera y la última cita (") de una variable

225

A continuación se muestra el fragmento de un script de shell de un script más grande. Elimina las comillas de la cadena que contiene una variable. Lo estoy haciendo usando sed, pero ¿es eficiente? Si no, ¿cuál es la forma eficiente?

#!/bin/sh

opt="\"html\\test\\\""
temp=`echo $opt | sed 's/.\(.*\)/\1/' | sed 's/\(.*\)./\1/'`
echo $temp
usuario1263746
fuente
Sugeriría usar sed "s/^\(\"\)\(.*\)\1\$/\2/g" <<<"$opt". Esta sintaxis eliminará qoutes solo cuando haya un par coincidente.
John Smith
@JohnSmith También tengo que escapar automáticamente de las comillas en un script de shell, pero necesito hacerlo si coinciden o no, por lo que probablemente no usaré esa expresión que publicaste.
Pysis
Si encontró esta pregunta mientras simplemente deseaba eliminar todas las comillas, vea esta respuesta: askubuntu.com/a/979964/103498 .
Gordon Bean

Respuestas:

268

Hay una manera más simple y eficiente, utilizando la función de eliminación de prefijo / sufijo de shell nativo:

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

${opt%\"}eliminará el sufijo "(se escapó con una barra diagonal inversa para evitar la interpretación de shell).

${temp#\"}eliminará el prefijo "(se escapó con una barra diagonal inversa para evitar la interpretación de shell).

Otra ventaja es que eliminará las comillas circundantes solo si hay comillas circundantes.

Por cierto, su solución siempre elimina el primer y el último carácter, sean los que sean (por supuesto, estoy seguro de que conoce sus datos, pero siempre es mejor estar seguro de lo que está eliminando).

Usando sed:

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

(Versión mejorada, como lo indica jfgagne, deshaciéndose del eco)

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

Por lo tanto, reemplaza un inicio "con nada y un final "sin nada también. En la misma invocación (no hay necesidad de canalizar e iniciar otro sed.-e puede tener procesamiento de texto múltiple).

huelbois
fuente
14
Puede deshacerse de la tubería en la solución sed con sed -e 's/^"//' -e 's/"$//' <<< $opt.
jfg956
1
Esto podría comportarse mal si la cadena no tiene un carácter de comillas inicial y final. ¿Alguna sugerencia para manejar eso con gracia?
jsears
Para manejar solo citas externas coincidentes, vea la respuesta de @Joachim Pileborg
jsears
1
@jsears ¿Eh? Esto recorta específicamente uno desde el principio si hay uno, y uno desde el final si hay uno. Si no desea eliminar a menos que ambos estén presentes; sí, se sedpodría usar una expresión regular única , o la sustitución de la variable podría estar envuelta en una líneacase $opt in '"'*'"') ... do it ... ;; esac
tripleee
2
Puede evitar las expresiones múltiples usandosed 's/^"\|"$//g'
tzrlk
287

Use tr para eliminar ":

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

Nota : Esto elimina todas las comillas dobles, no solo al principio y al final.

wieczorek1990
fuente
16
Esto no es lo que solicitó OP, ya que también elimina todas las comillas, no solo las iniciales y las finales.
Lenar Hoyt
19
Aunque no respondo explícitamente a OP, esto me resuelve porque solo hay comillas dobles al principio y al final de "/ path / file-name". No hay comillas dobles incrustadas. +1
WinEunuuchs2Unix
66
Esta solución será lo que mucha gente quiera. En muchos casos, las secuencias de comandos pueden reducir fácilmente los datos viables a una cadena rodeada de comillas.
Shadoninja
2
Elegante y me salvó de mucho más tiempo de prueba-error-depuración. Gracias.
Scott Wade
Esto es lo que idealmente se quiere y por eso tiene más votos que la respuesta aceptada.
apurvc
38

Esto eliminará todas las comillas dobles.

echo "${opt//\"}"
Steven Penny
fuente
1
Sin embargo, se romperá con citas escapado, por ejemplo, Don't remove this \" quote. :-(
gniourf_gniourf
Esta es una extensión Bash, por lo que no es aplicable para el script de shell en general. (La pregunta es ambigua en cuanto a si esto es importante o no visitantes que se encuentran en este Google podría estar buscando una solución POSIX..)
tripleee
¡Perfección! Exactamente lo que necesitaba. Me encantan las preguntas como esta que le dan una gran cantidad de respuestas, no solo lo que OP solicitó. ¡Las gemas están en las respuestas no aceptadas!
dlite922
Me temo que OP quiere algo que elimine solo las comillas iniciales / finales y mantenga las que se escapan.
Fernando Paz
36

Hay una manera sencilla de usar xargs :

> echo '"quoted"' | xargs
quoted

xargs usa echo como el comando predeterminado si no se proporciona ningún comando y elimina las comillas de la entrada. Ver, por ejemplo, aquí .

usuario1587520
fuente
echo '"quoted"' | xargs -> quoted
kyb
1
Esto funciona, pero solo para un número par de comillas en una cadena. Si hay un número impar, genera un error.
James Shewey
21

Puede hacerlo con solo una llamada a sed:

$ echo "\"html\\test\\\"" | sed 's/^"\(.*\)"$/\1/'
html\test\
Algún tipo programador
fuente
19

El camino más corto : intente:

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

En realidad, elimina todas las "s (comillas dobles) de opt(¿realmente habrá más comillas dobles que no sean al principio y al final? Entonces, en realidad es lo mismo, y mucho más breve ;-))

Dr. Kameleon
fuente
44
Si desea eliminar todas las comillas dobles, entonces es aún mejor usar: "$ {opt // \" /} ". Sin tubería, sin subshell ... Y tenga en cuenta que si tiene espacios en opt, puede perder las variables citarlos siempre así:. echo "$ opt"
huelbois
Bueno, la variable básicamente lee la ruta de DocumentRoot desde el archivo de configuración de httpd, por lo que no creo que haya un caso en el que posiblemente haya un carácter entre comillas en la cadena. Y este sed es mucho más ordenado y eficiente ... ¡Gracias!
user1263746
16

Si está utilizando jq e intenta eliminar las comillas del resultado, las otras respuestas funcionarán, pero hay una mejor manera. Al usar la -ropción, puede generar el resultado sin comillas.

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

$ echo '{"foo": "bar"}' | jq -r '.foo'
bar
aguafiestas
fuente
Estoy usando, jqpero tenga en cuenta que no funciona si jq también está emitiendo salida ASCII con -a(es un error al lado de jq)
Can Poyrazoğlu
yqtambién tiene -ropción:yq -r '.foo' file.yml
Hlib Babii
12

Actualizar

Una respuesta simple y elegante de Stripping comillas simples y dobles en una cadena usando solo comandos bash / Linux estándar :

BAR=$(eval echo $BAR) tiras de citas de BAR .

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

Basado en la respuesta de hueybois, se me ocurrió esta función después de mucho ensayo y error:

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

Si no desea imprimir nada, puede canalizar las evaluaciones a /dev/null 2>&1 .

Uso:

$ BAR="FOO BAR"
$ echo BAR
"FOO BAR"
$ stripStartAndEndQuotes "BAR"
$ echo BAR
FOO BAR
Jonathan Lin
fuente
1
Aunque realmente me gusta lo simple y elegante, creo que vale la pena notar que eval no solo hace recortes de comillas dobles, sino que en realidad se evalúa como una línea de código. Por lo tanto, esta técnica puede producir resultados inesperados cuando BAR contiene otras secuencias que pueden sustituir por el shell (por ejemplo, BAR = \ 'abc \' o BAR = ab \ 'c o BAR = a \ $ b, o BAR = a \ $ (ls *))
MaxP
11

La solución más fácil en Bash:

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

Esto se llama expansión de subcadena (consulte el Manual de Gnu Bash y busque ${parameter:offset:length}). En este ejemplo, la subcadena scomienza desde la posición 1 y termina en la segunda última posición. Esto se debe al hecho de que si lengthes un valor negativo, se interpreta como un desplazamiento hacia atrás desde el final de parameter.

Hiro.protagonista
fuente
longitudes negativas compatibles con bash v4.2
mr.spuratic
8

Esta es la forma más discreta sin usar sed:

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

O

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

Salida:

   quotes: "fish"
no quotes:  fish

Obtuve esto de una fuente .

nimig18
fuente
Esto eliminará las comillas dentro de la cadena, así como las que la rodean.
jsears
Aparte del comentario, esto es idéntico a la respuesta de @ StevenPenny de 2012 .
tripleee
3

Hay otra forma de hacerlo. Me gusta:

echo ${opt:1:-1}
DevilTour
fuente
2

Mi version

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 función acepta nombre (s) de variable y elimina comillas en su lugar. Solo elimina un par coincidente de comillas iniciales y finales. No comprueba si la cita final se escapa (precedida por\ cual no se escapa).

En mi experiencia, las funciones de utilidad de cadena de propósito general como esta (tengo una biblioteca de ellas) son más eficientes cuando se manipulan las cadenas directamente, no se utiliza ninguna coincidencia de patrones y, especialmente, no se crean subcapas ni se llaman herramientas externas como 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
Gene Pavlovsky
fuente
0

Sé que esta es una pregunta muy antigua, pero aquí hay otra variación de sed, que puede ser útil para alguien. A diferencia de algunos de los otros, solo reemplaza las comillas dobles al principio o al final ...

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