
En un bash
script, ¿cómo puedo eliminar una palabra de una cadena? La palabra se almacenaría en una variable.
FOO="CATS DOGS FISH MICE"
WORDTOREMOVE="MICE"
Respuesta1
Usando bash
reemplazo de subcadenas (copiado de ksh93):
FOO=${FOO//"$WORDTOREMOVE"/}
Reemplaza //
todas las apariciones de la subcadena ( $WORDTOREMOVE
) con el contenido entre /
y }
. En este caso nada.
Tenga en cuenta las comillas $WORDTOREMOVE
para asegurarse de que el contenido se tome como una cadena fija en lugar de un patrón.
Cuando el reemplazo está vacío, /
también se puede omitir: ${FOO//"$WORDTOREMOVE"}
.
Para obtener información sobre esta y otras formas de trabajar con cadenas en bash, consulte la sección10.1. Manipular cadenasdelGuía avanzada de secuencias de comandos Bash.
Respuesta2
Intentar:
$ printf '%s\n' "${FOO//"$WORDTOREMOVE"/}"
CATS DOGS FISH
Esto también funciona en ksh93
(de donde viene) mksh
y zsh
.
POSIX:
FOO="CATS DOGS FISH MICE"
WORDTOREMOVE="MICE"
remove_word() (
set -f
IFS=' '
s=$1
w=$2
set -- $1
for arg do
shift
[ "$arg" = "$w" ] && continue
set -- "$@" "$arg"
done
printf '%s\n' "$*"
)
remove_word "$FOO" "$WORDTOREMOVE"
Asume que sus palabras están delimitadas por espacios y tiene un efecto secundario que elimina los espacios antes y después "$WORDTOREMOVE"
.
Respuesta3
Puedes usarsed
como esto:
echo $FOO | sed s/"$WORDTOREMOVE"//
Respuesta4
Quitando unopalabrade una cadena que representa una lista de palabras delimitadas por espacios en blanco no es tan fácil, porque es necesario decidir qué hacer con el espacio en cada lado.
Incluso en una representación domesticada donde siempre hay un único espacio entre las palabras, es necesario diferenciar varios casos diferentes:
- palabra en el medio:
foo MICE bar
->foo bar
: palabra y los espacios antes y después reemplazados por un solo espacio.${var/+( )MICE+( )/ }
- palabra al principio:
MICE foo bar
->foo bar
: palabra y los espacios posteriores reemplazados por nada:${var/MICE+( )}
- palabra al final:
foo bar MICE
->foo bar
: palabra y los espacios anteriores reemplazados por nada:${var/+( )MICE}
. - luego está el problema de varias apariciones sucesivas de la palabra que
${var// MICE / }
no funcionaríanfoo MICE MICE bar
porque el primer reemplazo consumiría el espacio que precede al segundo MICE.
(arriba usando el ${var/pattern/replacement}
operador de ksh93).
Sin embargo, se vuelve más fácil si agrega un espacio al principio y al final antes de realizar la sustitución y los elimina después, ya que entonces puede cubrir todos los terrenos con un operador de sustitución:
var='MICE foo MICE MICE bar MICE'
word=MICE
var=" $var "
var=${var//+(+([[:space:]])"$word")+([[:space:]])/ }
var=${var# } var=${var% }
Necesitaría shopt -s extglob
bash o set -o kshglob
zsh de antemano para admitir que +([[:space:]])
el operador ksh88 coincida con 1 o más caracteres de espacio en blanco.
O usando zsh
el propio extendedglob
s ( set -o extendedglob
) donde ksh +(x)
se convierte en x##
:
var=${var//([[:space:]]##$word)##[[:space:]]##/ }
Incluso es posible restaurar el espacio que estaba antes o después de las palabras con (en zsh
; ksh93 tendría algo equivalente, no bash):
var='MICE foo MICE MICE bar MICE'
word=MICE
set -o extendedglob
var=" $var "
var=${var//(#b)([[:space:]]##$word)##([[:space:]]##)/$match[2]}
var=${var# } var=${var% }
Si en lugar de una variable escalar que contiene una representación de una lista, tienes una variable escalar reallista(matriz) variable, como en:
var=(MICE foo MICE MICE bar MICE)
Luego, el problema se reduce a eliminar elementos específicos de la matriz, lo que se vuelve trivial con shells con variables de matriz adecuadas, como (de donde proviene zsh
esa sintaxis):var=(foo bar)
var=( ${var:#$word} )