Strippen Sie einzelne und doppelte Zitate in einer Zeichenfolge nur mit Bash / Standard -Linux -Befehlen
Frage
Ich suche etwas, das eine Zeichenfolge wie folgt übersetzt und nur Bash / Standard -Linux -Befehle verwendet:
- Ein-Zitate, die eine Schnur umgeben, sollten entfernt werden
- Die umgebende Doppelquote, die eine Schnur umgeben, sollten entfernt werden
- Nicht zahlte Saiten sollten gleich bleiben
- Saiten mit unübertroffenen umgebenden Zitaten sollten gleich bleiben
- Ein-Zitate, die die Saite nicht umgeben, sollten bleiben
- Doppelquote, die die Saite nicht umgeben, sollte bleiben
Zum Beispiel:
- "Essen" sollte zu Essen werden
- "Essen" sollte zu Essen werden
- Essen sollte gleich bleiben
- 'Essen' sollte gleich bleiben
- "Essen" sollte gleich bleiben
- 'Fo'od' sollte für Fo'od werden
- "Fo'od" sollte fo'od werden
- Fo'od sollte gleich bleiben
- 'Fo "od' sollte für zu werden" od
- "Fo" od "sollte fo" od werden
- Fo "od sollte gleich bleiben
Vielen Dank!
Lösung
Dies sollte es tun:
sed "s/^\([\"']\)\(.*\)\1\$/\2/g" in.txt
Wo in.txt ist:
"Fo'od'
'Food'
"Food"
"Fo"od'
Food
'Food"
"Food'
'Fo'od'
"Fo'od"
Fo'od
'Fo"od'
"Fo"od"
Fo"od
Und erwartet.txt ist:
"Fo'od'
Food
Food
"Fo"od'
Food
'Food"
"Food'
Fo'od
Fo'od
Fo'od
Fo"od
Fo"od
Fo"od
Sie können überprüfen, ob sie übereinstimmen:
diff -s <(sed "s/^\([\"']\)\(.*\)\1\$/\2/g" in.txt) expected.txt
Andere Tipps
Du könntest benutzen tr
:
echo "$string" | tr -d 'chars to delete'
... auch funktioniert, aber "tr" ist jedoch als problematisch bei viel älteren (Circa Redhat 9-ISH) -Verteilungen bekannt. tr
ist eine Abkürzung für "Translate", die üblicherweise in Rohren verwendet wird, um die Eingabe zu transformieren. Das -d
Option bedeutet einfach 'löschen'.
Die meisten modernen Versionen enthalten auch vordefinierte Makros, um die obere nach unten nach unten nach oben nach oben zu transformieren, den weißen Raum abzutöten usw., wenn Sie ihn verwenden, nehmen Sie sich eine Sekunde Zeit, um zu stöbern, was es sonst noch tut (siehe Hilfeseiten / Mannseite). kommt nützlich.
VAR="'FOOD'"
VAR=$(eval echo $VAR)
Erläuterung: Da Zitate bereits von der Shell verstanden werden, können Sie die Shell bitten, einen Befehl zu bewerten, der nur die zitierte Zeichenfolge wiederholt, genauso wie sie es selbst eingeben.
Hier, eval echo $VAR
erweitert zu eval echo 'FOOD'
Weil die Zitate tatsächlich Teil des Wertes von sind VAR
. Wenn Sie rennen würden echo 'FOOD'
in die Hülle, die du bekommen würdest FOOD
(ohne die Anführungszeichen). Das ist, was eval
tut: Es nimmt seine Eingabe und führt es wie ein Shell -Befehl aus.
⚠Code Injection!
eval
Stellen Sie Skripte für die Codeinjektion aus.VAR=';ls -l' VAR=$(eval echo $VAR)
wird die Ausführung von verursachen
ls -l
.Hier könnten viel schädlichere Codes injiziert werden.
Sie möchten wahrscheinlich verwenden sed...
echo $mystring | sed -s "s/^\(\(\"\(.*\)\"\)\|\('\(.*\)'\)\)\$/\\3\\5/g"
Verwenden Sie nur BASH -BAHRE (dh Bash -Parameterausdehnung):
IFS=' '
food_strings=( "'Food'" '"Food"' Food "'Food\"" "\"Food'" "'Fo'od'" "\"Fo'od\"" "Fo'od" "'Fo\"od'" '"Fo"od"' 'Fo"od' )
for food in ${food_strings[@]}; do
[[ "${food#\'}" != "$food" ]] && [[ "${food%\'}" != "$food" ]] && { food="${food#\'}"; food="${food%\'}"; }
[[ "${food#\"}" != "$food" ]] && [[ "${food%\"}" != "$food" ]] && { food="${food#\"}"; food="${food%\"}"; }
echo "$food"
done
Für ein weiteres Beispiel für eine Bash -Parameterausdehnung siehe:
Ich bin gerade auch darauf gestoßen. In den ersten drei Testfällen,, eval echo $string
funktioniert gut. Damit es für alle angeforderten und ein paar anderen Fälle funktioniert, habe ich mich ausgedacht (getestet mit bash
und dash
):
#!/bin/sh
stripquotes() {
local firstchar="`substr "$1" 0 1`"
local len=${#1}
local ilast=$((${#1} - 1))
local lastchar="`substr "$1" $(($len - 1))`"
if [ "$firstchar" = '"' ] || [ "$firstchar" = "'" ] && [ $firstchar = $lastchar ]; then
echo "`substr "$1" 1 $(($len - 2))`"
else
echo "$1"
fi
}
# $1 = String.
# $2 = Start index.
# $3 = Length (optional). If unspecified or an empty string, the length of the
# rest of the string is used.
substr() {
local "len=$3"
[ "$len" = '' ] && len=${#1}
if ! (echo ${1:$2:$len}) 2>/dev/null; then
echo "$1" | awk "{ print(substr(\$0, $(($2 + 1)), $len)) }"
fi
}
var="'Food'"
stripquotes "$var"
var='"Food"'
stripquotes "$var"
var=Food
stripquotes "$var"
var=\'Food\"
stripquotes "$var"
var=\"Food\'
stripquotes "$var"
var="'Fo'od'"
stripquotes "$var"
var="\"Fo'od\""
stripquotes "$var"
var="Fo'od"
stripquotes "$var"
var="'Fo\"od'"
stripquotes "$var"
var="\"Fo\"od\""
stripquotes "$var"
var="Fo\"od"
stripquotes "$var"
# A string with whitespace should work too.
var="'F\"o 'o o o' o\"d'"
stripquotes "$var"
# Strings that start and end with the same character that isn't a quote or
# doublequote should stay the same.
var="TEST"
stripquotes "$var"
# An empty string should not cause errors.
var=
stripquotes "$var"
# Strings of length 2 that begin and end with a quote or doublequote should not
# cause errors.
var="''"
stripquotes "$var"
var='""'
stripquotes "$var"
python -c "import sys;a=sys.stdin.read();a=a.strip();print (a[1:-1] if a[0]==a[-1] and a[0] in \"'\\\"\" else a)"
Es handelt sich nicht um Kantenfälle (z. B. eine leere Schnur), aber es wird als Ausgangspunkt dienen. Es funktioniert, indem es den vorderen und hinteren Charakter streift, wenn sie gleich sind und ob sie 'oder "sind