Spogliarello virgolette singole e doppie in una stringa utilizzando bash / solo i comandi standard di Linux
Domanda
Sto cercando qualcosa che tradurre una stringa come segue, utilizzando solo bash / comandi standard di Linux:
- singole virgolette che circondano una stringa dovrebbero essere rimossi
- virgolette che circondano una stringa dovrebbero essere rimossi
- stringhe non quotati dovrebbero rimanere gli stessi
- stringhe con le virgolette che circondano senza eguali dovrebbe rimanere lo stesso
- Single-citazioni che non circondano la stringa dovrebbe rimanere
- virgolette che non circondano la stringa dovrebbe rimanere
Ad esempio:
- 'Food' dovrebbe diventare alimentare
- "Food" dovrebbe diventare alimentare
- Il cibo dovrebbe rimanere lo stesso
- 'Food" dovrebbe rimanere lo stesso
- "Food' dovrebbe rimanere lo stesso
- 'Fo'od' dovrebbe diventare Fo'od
- "Fo'od" dovrebbe diventare Fo'od
- Fo'od dovrebbe rimanere lo stesso
- 'Fo "od' dovrebbe diventare Fo" od
- "Fo" od "dovrebbe diventare Fo" od
- Fo "od dovrebbe rimanere lo stesso
Grazie!
Soluzione
Questo dovrebbe farlo:
sed "s/^\([\"']\)\(.*\)\1\$/\2/g" in.txt
Dove in.txt è:
"Fo'od'
'Food'
"Food"
"Fo"od'
Food
'Food"
"Food'
'Fo'od'
"Fo'od"
Fo'od
'Fo"od'
"Fo"od"
Fo"od
E expected.txt è:
"Fo'od'
Food
Food
"Fo"od'
Food
'Food"
"Food'
Fo'od
Fo'od
Fo'od
Fo"od
Fo"od
Fo"od
È possibile controllare che corrispondano con:
diff -s <(sed "s/^\([\"']\)\(.*\)\1\$/\2/g" in.txt) expected.txt
Altri suggerimenti
È possibile utilizzare tr
:
echo "$string" | tr -d 'chars to delete'
... funziona anche, però 'tr' è noto per essere problematico su gran parte anziani (circa Redhat 9-ish) distribuzioni. tr
è l'abbreviazione di 'tradurre', comunemente utilizzati in tubazioni per trasformare ingresso. L'opzione -d
significa semplicemente 'delete'.
La maggior parte delle versioni moderne contengono anche macro predefinite per trasformare superiore a quella inferiore, inferiore a superiore, di uccidere uno spazio bianco, ecc Quindi, se lo si utilizza, prendere un secondo a colpire in che altro lo fa (vedi l'aiuto di uscita / uomo pagina), è utile.
VAR="'FOOD'"
VAR=$(eval echo $VAR)
Spiegazione: Dal momento che citazioni sono già comprese dalla shell è possibile chiedere il guscio per valutare un comando che solo echos la stringa tra virgolette, allo stesso modo in cui funziona quando si digita da soli
. Qui, eval echo $VAR
espande per eval echo 'FOOD'
perché le quotazioni sono in realtà parte del valore della VAR
. Se si dovesse eseguire echo 'FOOD'
nella shell si otterrebbe FOOD
(senza le virgolette). Questo è ciò che fa eval
:. Prende il suo ingresso e lo esegue come un comando di shell
⚠CODE INIEZIONE!
eval
esporre gli script per l'iniezione di codice.VAR=';ls -l' VAR=$(eval echo $VAR)
causerà esecuzione
ls -l
.molto più dannosi codici potrebbero essere iniettati qui.
Probabilmente si desidera utilizzare sed ...
echo $mystring | sed -s "s/^\(\(\"\(.*\)\"\)\|\('\(.*\)'\)\)\$/\\3\\5/g"
Proprio utilizzando builtins Bash (vale a dire Bash espansione di parametro):
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
Per l'ennesimo esempio di Bash espansione di parametro vedi:
Proprio imbattuto in questo pure. Per i primi tre casi di test, eval echo $string
funziona bene. Per farlo funzionare per tutti i casi richiesti e pochi altri, sono arrivato fino a questo (testato con bash
e 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)"
non gestisce casi limite estremamente bene (come una stringa vuota), ma servirà come punto di partenza. Funziona striping carattere anteriore e posteriore se sono lo stesso e se sono 'o "