Script shell - supprime la première et la dernière citation (") d'une variable

225

Vous trouverez ci-dessous l'extrait d'un script shell à partir d'un script plus grand. Il supprime les guillemets de la chaîne qui est détenue par une variable. Je le fais en utilisant sed, mais est-ce efficace? Sinon, quel est le moyen efficace?

#!/bin/sh

opt="\"html\\test\\\""
temp=`echo $opt | sed 's/.\(.*\)/\1/' | sed 's/\(.*\)./\1/'`
echo $temp
user1263746
la source
Je suggère d'utiliser sed "s/^\(\"\)\(.*\)\1\$/\2/g" <<<"$opt". Cette syntaxe supprimera qoutes uniquement lorsqu'il existe une paire correspondante.
John Smith
@JohnSmith Je dois également échapper automatiquement les guillemets dans un script shell, mais je dois le faire, qu'ils correspondent ou non, donc je n'utiliserai probablement pas l'expression que vous avez publiée.
Pysis
Si vous avez trouvé cette question tout en souhaitant simplement supprimer toutes les citations, consultez cette réponse: askubuntu.com/a/979964/103498 .
Gordon Bean

Réponses:

268

Il existe un moyen plus simple et plus efficace d'utiliser la fonction de suppression native du préfixe / suffixe du shell:

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

${opt%\"}supprimera le suffixe "(échappé avec une barre oblique inverse pour empêcher l'interprétation du shell).

${temp#\"}supprimera le préfixe "(échappé avec une barre oblique inverse pour empêcher l'interprétation du shell).

Un autre avantage est qu'il ne supprimera les guillemets environnants que s'il y a des guillemets environnants.

BTW, votre solution supprime toujours le premier et le dernier caractère, quels qu'ils soient (bien sûr, je suis sûr que vous connaissez vos données, mais il vaut toujours mieux être sûr de ce que vous supprimez).

Utilisation de sed:

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

(Version améliorée, comme indiqué par jfgagne, se débarrasser de l'écho)

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

Ainsi, il remplace un début "par rien et un suivi "par rien aussi. Dans le même appel (il n'est pas nécessaire de diriger et de démarrer un autre sed. En utilisant, -evous pouvez avoir plusieurs traitements de texte).

huelbois
la source
14
Vous pouvez vous débarrasser du tuyau dans la solution sed avec sed -e 's/^"//' -e 's/"$//' <<< $opt.
jfg956
1
Cela pourrait mal se comporter si la chaîne n'a pas à la fois un caractère de guillemet de début et de fin. Des suggestions pour gérer cela avec élégance?
jsears
Pour gérer uniquement les citations externes correspondantes, voir la réponse de @Joachim Pileborg
jsears
1
@jsears Huh? Cela coupe spécifiquement un dès le début s'il y en a un, et un depuis la fin s'il y en a un. Si vous ne souhaitez pas supprimer à moins que les deux soient présents; oui, un seul sedregex pourrait être utilisé, ou la substitution de variable pourrait être case $opt in '"'*'"') ... do it ... ;; esac
encapsulée
2
Vous pouvez éviter les expressions multiples en utilisantsed 's/^"\|"$//g'
tzrlk
287

Utilisez tr pour supprimer ":

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

Remarque : Cela supprime tous les guillemets doubles, pas seulement les premiers et les derniers.

wieczorek1990
la source
16
Ce n'est pas ce que OP a demandé car il supprime également toutes les citations, pas seulement les guillemets principaux et finaux.
Lenar Hoyt
19
Bien que ne répondant pas explicitement à OP, cela résout pour moi car il n'y a que des guillemets doubles au début et à la fin de "/ chemin / nom de fichier". Il n'y a pas de guillemets intégrés. +1
WinEunuuchs2Unix
6
Cette solution sera ce que beaucoup de gens veulent. Dans de nombreux cas, les scripts peuvent facilement ramener les données exploitables à une chaîne entourée de guillemets.
Shadoninja
2
Élégant et m'a sauvé de beaucoup plus de temps d'essai-erreur-débogage. THX.
Scott Wade
C'est ce que l'on veut idéalement et c'est pourquoi il a plus de votes que la réponse acceptée.
apurvc
38

Cela supprimera tous les guillemets doubles.

echo "${opt//\"}"
Steven Penny
la source
1
Mais rompra avec les guillemets échappés, par exemple Don't remove this \" quote. :-(
gniourf_gniourf
Il s'agit d'une extension Bash, donc non applicable au script shell en général. (La question est ambiguë de savoir si cela est important ou non. Les visiteurs qui trouvent cela dans Google pourraient être à la recherche d'une solution POSIX.)
tripleee
La perfection! Exactement ce dont j'avais besoin. J'adore les questions comme celle-ci qui vous donnent une pléthore de réponses, pas seulement ce qu'OP a demandé. Les joyaux sont dans les réponses non acceptées!
dlite922
Je crains qu'OP ne veuille quelque chose qui supprime uniquement les guillemets de début / fin et conserve les échappés.
Fernando Paz
36

Il existe un moyen simple d'utiliser xargs :

> echo '"quoted"' | xargs
quoted

xargs utilise echo comme commande par défaut si aucune commande n'est fournie et supprime les guillemets de l'entrée. Voir par exemple ici .

user1587520
la source
echo '"quoted"' | xargs -> quoted
kyb
1
Cela fonctionne, mais uniquement pour un nombre pair de guillemets dans une chaîne. S'il y a un nombre impair, il génère une erreur.
James Shewey
21

Vous pouvez le faire avec un seul appel à sed:

$ echo "\"html\\test\\\"" | sed 's/^"\(.*\)"$/\1/'
html\test\
Un mec programmeur
la source
19

Le chemin le plus court - essayez:

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

Cela supprime en fait tous les "s (guillemets doubles) de opt(y aura-t-il vraiment plus de guillemets doubles qu'au début et à la fin? Donc, c'est en fait la même chose, et beaucoup plus bref ;-))

Dr.Kameleon
la source
4
Si vous voulez supprimer tous les guillemets, il est encore mieux d'utiliser: "$ {opt // \" /} ". Pas de pipe, pas de sous-shell ... Et attention, si vous avez des espaces dans opt, vous risquez de perdre Citez toujours des variables comme: echo "$ opt"
huelbois
Eh bien, la variable lit essentiellement le chemin de DocumentRoot à partir du fichier de configuration de httpd, donc je ne pense pas qu'il puisse y avoir un cas où un caractère de citation pourrait être là dans la chaîne. Et ce sed est beaucoup plus soigné et efficace .... Merci!
user1263746
16

Si vous utilisez jq et essayez de supprimer les guillemets du résultat, les autres réponses fonctionneront, mais il existe une meilleure façon. En utilisant l' -roption, vous pouvez afficher le résultat sans guillemets.

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

$ echo '{"foo": "bar"}' | jq -r '.foo'
bar
killjoy
la source
J'utilise jqmais veuillez noter que cela ne fonctionne pas si jq génère également une sortie ASCII avec -a(c'est un bogue du côté de jq)
Can Poyrazoğlu
yqa également l' -roption:yq -r '.foo' file.yml
Hlib Babii
12

Mettre à jour

Une réponse simple et élégante de suppression des guillemets simples et doubles dans une chaîne en utilisant uniquement les commandes bash / standard Linux :

BAR=$(eval echo $BAR)dépouille les citations de BAR.

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

Sur la base de la réponse de hueybois, j'ai trouvé cette fonction après de nombreux essais et erreurs:

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

Si vous ne voulez rien imprimer, vous pouvez /dev/null 2>&1 .

Usage:

$ BAR="FOO BAR"
$ echo BAR
"FOO BAR"
$ stripStartAndEndQuotes "BAR"
$ echo BAR
FOO BAR
Jonathan Lin
la source
1
Bien que j'aime vraiment le simple et l'élégant, je pense qu'il vaut la peine de noter qu'eval ne fait pas que des doublures de guillemets doubles, mais qu'il est en fait évalué comme une ligne de code. Par conséquent, cette technique peut donner des résultats inattendus lorsque BAR contient d'autres séquences qui peuvent se substituer par le shell (par exemple BAR = \ 'abc \' ou BAR = ab \ 'c ou BAR = a \ $ b, ou BAR = a \ $ (ls *))
MaxP
11

La solution la plus simple dans Bash:

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

C'est ce qu'on appelle l'expansion de la sous-chaîne (voir Gnu Bash Manual et rechercher ${parameter:offset:length}). Dans cet exemple, la sous-chaîne scommence à la position 1 et se termine à l'avant-dernière position. Cela est dû au fait que si lengthest une valeur négative, elle est interprétée comme un décalage vers l'arrière à partir de la fin de parameter.

Hiro.Protagonist
la source
longueurs négatives prises en charge par bash v4.2
mr.spuratic
8

C'est le moyen le plus discret sans utiliser sed:

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

Ou

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

Production:

   quotes: "fish"
no quotes:  fish

Je l'ai obtenu d' une source .

nimig18
la source
Cela supprimera les guillemets de la chaîne ainsi que ceux qui l'entourent.
jsears
Mis à part le commentaire, cela est identique à la réponse de @ StevenPenny de 2012 .
tripleee
3

Il y a une autre façon de procéder. Comme:

echo ${opt:1:-1}
DevilTour
la source
2

Ma 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 fonction accepte les noms de variable et supprime les guillemets en place. Il supprime uniquement une paire correspondante de guillemets de début et de fin. Il ne vérifie pas si le guillemet de fin est échappé (précédé de\ laquelle n'est pas elle-même échappée).

D'après mon expérience, les fonctions utilitaires de chaîne à usage général comme celle-ci (j'en ai une bibliothèque) sont plus efficaces lors de la manipulation directe des chaînes, sans utiliser de correspondance de modèle et surtout sans créer de sous-shells, ou appeler des outils externes tels que 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
la source
0

Je sais que c'est une très vieille question, mais voici une autre variante sed, qui peut être utile à quelqu'un. Contrairement à certains autres, il ne remplace que les guillemets doubles au début ou à la fin ...

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