Excluyendo comillas simples y dobles en una cadena utilizando bash / Linux estándar comandos sólo
Pregunta
Estoy buscando algo que va a traducir una cadena de la siguiente manera, utilizando sólo bash / Linux estándar comandos:
- comillas simples que rodean una cadena deben ser retirados
- comillas dobles que rodean una cadena deben ser retirados
- cadenas Unquoted deben seguir siendo la misma
- Cuerdas con citas de los alrededores inigualables debe seguir siendo el mismo
- comillas simples que no rodean la cadena deben permanecer
- comillas dobles que no rodean la cadena deben permanecer
Por ejemplo:
- 'Alimentación' debe convertirse en Alimentaria
- "alimento" debe convertirse en Alimentaria
- Los alimentos deben seguir siendo el mismo
- 'Alimentos" debe seguir siendo el mismo
- "alimento' debe seguir siendo el mismo
- 'Fo'od' debe convertirse en Fo'od
- "Fo'od" debe convertirse en Fo'od
- Fo'od debe seguir siendo el mismo
- 'Fo "od' debe convertirse en Fo" od
- "Fo" od "debe convertirse en Fo" od
- Fo "od debe seguir siendo el mismo
Gracias!
Solución
Esto debe hacerlo:
sed "s/^\([\"']\)\(.*\)\1\$/\2/g" in.txt
Cuando in.txt es:
"Fo'od'
'Food'
"Food"
"Fo"od'
Food
'Food"
"Food'
'Fo'od'
"Fo'od"
Fo'od
'Fo"od'
"Fo"od"
Fo"od
Y expected.txt es:
"Fo'od'
Food
Food
"Fo"od'
Food
'Food"
"Food'
Fo'od
Fo'od
Fo'od
Fo"od
Fo"od
Fo"od
Puede comprobar que coinciden con:
diff -s <(sed "s/^\([\"']\)\(.*\)\1\$/\2/g" in.txt) expected.txt
Otros consejos
Se puede usar tr
:
echo "$string" | tr -d 'chars to delete'
... también funciona, sin embargo 'tr' es conocido por ser problemático en distribuciones RedHat (alrededor de 9-ish) mucho mayores. tr
es una abreviatura de 'traducir', comúnmente utilizado en tuberías para transformar de entrada. La opción -d
simplemente significa 'borrar'.
La mayoría de las versiones modernas también contienen macros predefinidas para transformar superior a la inferior, inferior a superior, matar a los espacios en blanco, etc. Por lo tanto, si usted lo usa, tomar un segundo para empujar a lo demás que sí (ver el resultado de la ayuda / hombre página), viene muy bien.
VAR="'FOOD'"
VAR=$(eval echo $VAR)
Explicación: Dado que las cotizaciones ya son entendidos por la cáscara puede pedirle a la cáscara para evaluar un comando que simplemente hace eco de la cadena entre comillas, de la misma manera que lo hace cuando se escribe usted mismo
. A continuación, se expande para eval echo $VAR
eval echo 'FOOD'
debido a que las citas son en realidad parte del valor de VAR
. Si se va a ejecutar echo 'FOOD'
en la cáscara se obtendría FOOD
(sin las comillas). Eso es lo que hace eval
:. Que toma su entrada y lo ejecuta como un comando shell
⚠CODE INYECCIÓN!
eval
exponer scripts para inyección de código.VAR=';ls -l' VAR=$(eval echo $VAR)
hará que la ejecución de
ls -l
.códigos mucho más dañina podrían inyectarse aquí.
Es posible que desee utilizar sed ...
echo $mystring | sed -s "s/^\(\(\"\(.*\)\"\)\|\('\(.*\)'\)\)\$/\\3\\5/g"
Sólo usando builtins Bash (es decir, la expansión de parámetro Bash):
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
En todavía otro ejemplo de Bash expansión de parámetro, véase:
tropecé con esto también. Durante los tres primeros casos de prueba, eval echo $string
funciona bien. Para conseguir que funcione para todos los casos solicitados y algunos otros, se me ocurrió esto (probado con bash
y 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)"
no maneja casos extremos muy bien (como una cadena vacía), pero servirá como punto de partida. Funciona mediante la creación de bandas el carácter frontal y posterior si son los mismos y si son "o "