Shell-Skript - Entfernen Sie das erste und letzte Anführungszeichen (") aus einer Variablen

225

Unten finden Sie den Ausschnitt eines Shell-Skripts aus einem größeren Skript. Es entfernt die Anführungszeichen aus der Zeichenfolge, die von einer Variablen gehalten wird. Ich mache es mit sed, aber ist es effizient? Wenn nicht, wie geht es dann effizient?

#!/bin/sh

opt="\"html\\test\\\""
temp=`echo $opt | sed 's/.\(.*\)/\1/' | sed 's/\(.*\)./\1/'`
echo $temp
user1263746
quelle
Ich würde vorschlagen, zu verwenden sed "s/^\(\"\)\(.*\)\1\$/\2/g" <<<"$opt". Diese Syntax entfernt Qoutes nur, wenn ein übereinstimmendes Paar vorhanden ist.
John Smith
@JohnSmith Ich muss auch Anführungszeichen in einem Shell-Skript automatisch maskieren, aber ich muss dies tun, ob sie übereinstimmen oder nicht, daher werde ich den von Ihnen geposteten Ausdruck wahrscheinlich nicht verwenden.
Pysis
Wenn Sie diese Frage gefunden haben, während Sie einfach alle Anführungszeichen entfernen möchten, lesen Sie diese Antwort: askubuntu.com/a/979964/103498 .
Gordon Bean

Antworten:

268

Es gibt eine einfachere und effizientere Möglichkeit, die native Funktion zum Entfernen von Shell-Präfixen / Suffixen zu verwenden:

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

${opt%\"}entfernt das Suffix "(mit einem Backslash versehen, um die Interpretation der Shell zu verhindern).

${temp#\"}entfernt das Präfix "(mit einem Backslash versehen, um eine Shell-Interpretation zu verhindern).

Ein weiterer Vorteil besteht darin, dass umgebende Anführungszeichen nur entfernt werden, wenn umgebende Anführungszeichen vorhanden sind.

Übrigens entfernt Ihre Lösung immer das erste und das letzte Zeichen, egal wie sie aussehen (natürlich bin ich sicher, dass Sie Ihre Daten kennen, aber es ist immer besser, sicher zu sein, was Sie entfernen).

Mit sed:

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

(Verbesserte Version, wie von jfgagne angezeigt, Echo loswerden)

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

Es ersetzt also eine Führung "durch nichts und eine Spur "durch nichts. Im selben Aufruf (es ist nicht erforderlich, ein anderes Sed weiterzuleiten und zu starten. Mit können -eSie mehrere Textverarbeitungen durchführen).

Huelbois
quelle
14
Sie können das Rohr in der sed-Lösung mit loswerden sed -e 's/^"//' -e 's/"$//' <<< $opt.
jfg956
1
Dies könnte sich schlecht verhalten, wenn die Zeichenfolge nicht sowohl ein führendes als auch ein nachfolgendes Anführungszeichen enthält. Irgendwelche Vorschläge, wie man das anmutig handhabt?
jsears
Um nur übereinstimmende äußere Anführungszeichen zu behandeln, lesen Sie die Antwort von @Joachim Pileborg
jsears
1
@jsears Huh? Dies schneidet speziell einen von Anfang an ab, wenn es einen gibt, und einen vom Ende, wenn es einen gibt. Wenn Sie nicht entfernen möchten, es sei denn, beide sind vorhanden. Ja, ein einzelner sedcase $opt in '"'*'"') ... do it ... ;; esac
regulärer Ausdruck
2
Sie könnten die mehrfachen Ausdrücke vermeiden, indem Siesed 's/^"\|"$//g'
tzrlk
287

Verwenden Sie tr zum Löschen ":

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

Hinweis : Dadurch werden alle doppelten Anführungszeichen entfernt, nicht nur führende und nachfolgende.

wieczorek1990
quelle
16
Dies ist nicht das, wonach OP gefragt hat, da es auch alle Anführungszeichen entfernt, nicht nur die führenden und nachfolgenden.
Lenar Hoyt
19
Obwohl ich OP nicht explizit beantworte, löst dies für mich eine Lösung, da am Anfang und am Ende von "/ path / file-name" nur doppelte Anführungszeichen stehen. Es gibt keine eingebetteten doppelten Anführungszeichen. +1
WinEunuuchs2Unix
6
Diese Lösung wird das sein, was viele Leute wollen. In vielen Fällen können durch Skripterstellung die verarbeitbaren Daten leicht in eine Zeichenfolge umgewandelt werden, die von Anführungszeichen umgeben ist.
Shadoninja
2
Elegant und ersparte mir viel mehr Zeit zum Ausprobieren. Vielen Dank.
Scott Wade
Dies ist, was man idealerweise will und deshalb hat es mehr Stimmen als die akzeptierte Antwort.
Apurvc
38

Dadurch werden alle doppelten Anführungszeichen entfernt.

echo "${opt//\"}"
Steven Penny
quelle
1
Wird aber mit entkommenen Anführungszeichen brechen, z Don't remove this \" quote. :-(
gniourf_gniourf
Dies ist eine Bash-Erweiterung, die im Allgemeinen nicht für Shell-Skripte gilt. (Die Frage ist nicht eindeutig, ob dies wichtig ist oder nicht. Besucher, die dies in Google finden, suchen möglicherweise nach einer POSIX-Lösung.)
Tripleee
Perfektion! Genau das, was ich brauchte. Ich liebe Fragen wie diese, die Ihnen eine Vielzahl von Antworten geben, nicht nur das, was OP verlangt hat. Die Edelsteine ​​sind in den nicht akzeptierten Antworten!
dlite922
Ich fürchte, OP möchte etwas, das nur führende / nachfolgende Anführungszeichen entfernt und die entkommenen Anführungszeichen beibehält.
Fernando Paz
36

Es gibt eine einfache Möglichkeit, xargs zu verwenden :

> echo '"quoted"' | xargs
quoted

xargs verwendet echo als Standardbefehl, wenn kein Befehl angegeben ist, und entfernt Anführungszeichen von der Eingabe. Siehe zB hier .

user1587520
quelle
echo '"quoted"' | xargs -> quoted
Kyb
1
Dies funktioniert jedoch nur für eine gerade Anzahl von Anführungszeichen in einer Zeichenfolge. Wenn es eine ungerade Zahl gibt, wird ein Fehler generiert.
James Shewey
21

Sie können dies mit nur einem Anruf tun sed:

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

Der kürzeste Weg - versuchen Sie:

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

Es werden tatsächlich alle "s (doppelte Anführungszeichen) entfernt opt(gibt es wirklich mehr doppelte Anführungszeichen als am Anfang und am Ende? Also ist es tatsächlich dasselbe und viel kürzer ;-))

Dr.Kameleon
quelle
4
Wenn Sie alle doppelten Anführungszeichen entfernen möchten, ist es noch besser, "$ {opt // \" /} "zu verwenden. Keine Pipe, keine Subshell ... Und Vorsicht, wenn Sie Leerzeichen in opt haben, können Sie verlieren zitieren Sie immer Variablen wie: echo "$ opt"
huelbois
Nun, die Variable liest im Grunde den Pfad von DocumentRoot aus der Konfigurationsdatei von httpd, daher glaube ich nicht, dass es einen Fall geben könnte, in dem möglicherweise ein Anführungszeichen in der Zeichenfolge vorhanden ist. Und dieses Sed ist viel ordentlicher und effizienter ... Danke!
user1263746
16

Wenn Sie jq verwenden und versuchen, die Anführungszeichen aus dem Ergebnis zu entfernen, funktionieren die anderen Antworten, aber es gibt einen besseren Weg. Mit der -rOption können Sie das Ergebnis ohne Anführungszeichen ausgeben.

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

$ echo '{"foo": "bar"}' | jq -r '.foo'
bar
Killjoy
quelle
Ich benutze, jqaber bitte beachten Sie, dass es nicht funktioniert, wenn jq auch ASCII-Ausgabe mit ausgibt -a(es ist ein Fehler an der Seite von jq)
Can Poyrazoğlu
yqhat auch -rOption:yq -r '.foo' file.yml
Hlib Babii
12

Aktualisieren

Eine einfache und elegante Antwort aus dem Entfernen von einfachen und doppelten Anführungszeichen in einer Zeichenfolge nur mit bash / Standard-Linux-Befehlen :

BAR=$(eval echo $BAR)Streifen Zitate aus BAR.

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

Basierend auf der Antwort von hueybois habe ich mir diese Funktion nach langem Ausprobieren ausgedacht:

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

Wenn Sie nicht möchten, dass etwas ausgedruckt wird, können Sie die Auswertungen an weiterleiten /dev/null 2>&1 .

Verwendung:

$ BAR="FOO BAR"
$ echo BAR
"FOO BAR"
$ stripStartAndEndQuotes "BAR"
$ echo BAR
FOO BAR
Jonathan Lin
quelle
1
Obwohl ich das Einfache und Elegante wirklich mag, denke ich, dass es erwähnenswert ist, dass eval nicht nur doppelte Anführungszeichen macht, sondern tatsächlich als Codezeile ausgewertet wird. Daher kann diese Technik zu unerwarteten Ergebnissen führen, wenn BAR andere Sequenzen enthält, die durch die Shell ersetzt werden können (z. B. BAR = \ 'abc \' oder BAR = ab \ 'c oder BAR = a \ $ b oder BAR = a \ $ (ls) *))
MaxP
11

Die einfachste Lösung in Bash:

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

Dies wird als Teilzeichenfolgenerweiterung bezeichnet (siehe Gnu Bash-Handbuch und Suche nach ${parameter:offset:length}). In diesem Beispiel sbeginnt der Teilstring an Position 1 und endet an der vorletzten Position. Dies liegt an der Tatsache, dass lengthein negativer Wert als rückwärts laufender Versatz vom Ende von interpretiert wird parameter.

Hiro.Protagonist
quelle
negative Längen unterstützt von bash v4.2
mr.spuratic
8

Dies ist der diskreteste Weg ohne sed:

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

Oder

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

Ausgabe:

   quotes: "fish"
no quotes:  fish

Ich habe das von einer Quelle bekommen .

nimig18
quelle
Dadurch werden Anführungszeichen aus der Zeichenfolge sowie aus den umgebenden Zeichenfolgen entfernt.
jsears
Abgesehen vom Kommentar ist dies identisch mit der Antwort von @ StevenPenny aus dem Jahr 2012 .
Tripleee
3

Es gibt noch einen anderen Weg. Mögen:

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

Meine 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
}

Die Funktion akzeptiert Variablennamen und entfernt Anführungszeichen. Es werden nur ein passendes Paar führender und nachfolgender Anführungszeichen entfernt. Es wird nicht überprüft, ob das nachfolgende Anführungszeichen maskiert ist (vorangestellt von\ dem es nicht selbst maskiert ist).

Nach meiner Erfahrung sind solche universellen Zeichenfolgen-Dienstprogrammfunktionen (ich habe eine Bibliothek davon) am effizientesten, wenn Sie die Zeichenfolgen direkt bearbeiten, keinen Mustervergleich verwenden und insbesondere keine Unterschalen erstellen oder externe Tools wie z sed, awkoder 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
quelle
0

Ich weiß, dass dies eine sehr alte Frage ist, aber hier ist eine andere sed-Variante, die für jemanden nützlich sein kann. Im Gegensatz zu einigen anderen ersetzt es nur doppelte Anführungszeichen am Anfang oder Ende ...

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