Удалить определенное слово в переменной

Удалить определенное слово в переменной

Как в bashскрипте удалить слово из строки? Слово будет сохранено в переменной.

FOO="CATS DOGS FISH MICE"
WORDTOREMOVE="MICE"

решение1

Использование bashзамены подстроки (скопировано из ksh93):

FOO=${FOO//"$WORDTOREMOVE"/}

Заменяет //все вхождения подстроки ( $WORDTOREMOVE) содержимым между /и }. В этом случае ничего.

Обратите внимание на кавычки, $WORDTOREMOVEчтобы убедиться, что содержимое воспринимается как фиксированная строка, а не шаблон.

Если замена пуста, то /можно также опустить: ${FOO//"$WORDTOREMOVE"}.

Информацию об этом и других способах работы со строками в bash см. в разделе10.1 Манипулирование строкамипринадлежащийРасширенное руководство по написанию сценариев Bash.

решение2

Пытаться:

$ printf '%s\n' "${FOO//"$WORDTOREMOVE"/}"
CATS DOGS FISH

Это также работает в ksh93(откуда оно пришло), mkshи zsh.


POSIXLy:

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"

Он предполагает, что ваши слова разделены пробелами, и имеет побочный эффект, который удаляет пробелы до и после "$WORDTOREMOVE".

решение3

Вы можете использоватьsedтак:

echo $FOO | sed s/"$WORDTOREMOVE"//

решение4

Удаление одногословоиз строки, представляющей собой список слов, разделенных пробелами, не так-то просто, поскольку вам нужно решить, что делать с пробелами с каждой стороны.

Даже в упрощенном представлении, где между словами всегда есть один пробел, необходимо различать несколько случаев:

  • слово в середине: foo MICE bar-> foo bar: слово и пробелы до и после него заменены одним пробелом.${var/+( )MICE+( )/ }
  • слово в начале: MICE foo bar-> foo bar: слово и пробелы после него заменены ничем:${var/MICE+( )}
  • слово в конце: foo bar MICE-> foo bar: слово и пробелы перед ним заменены ничем: ${var/+( )MICE}.
  • затем возникает проблема нескольких последовательных вхождений слова where, которое ${var// MICE / }не будет работать, foo MICE MICE barпоскольку первая замена съест пространство, предшествующее второму MICE.

(выше с использованием ${var/pattern/replacement}оператора из ksh93).

Однако все становится проще, если вы добавите пробел в начале и в конце перед выполнением замены и удалите их впоследствии, поскольку тогда вы сможете охватить все области одним оператором замены:

var='MICE foo MICE MICE bar MICE'
word=MICE

var=" $var "
var=${var//+(+([[:space:]])"$word")+([[:space:]])/ }
var=${var# } var=${var% }

Вам необходимо заранее shopt -s extglobв bash или set -o kshglobzsh реализовать поддержку +([[:space:]])оператора ksh88 для сопоставления одного или нескольких пробельных символов.

Или используя zshсобственный extendedglobs( set -o extendedglob), где ksh's +(x)становится x##:

var=${var//([[:space:]]##$word)##[[:space:]]##/ }

Можно даже восстановить пробел, который был после или перед словами, с помощью (в zsh; в ksh93 было бы что-то эквивалентное, а не в 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% }

Если вместо скалярной переменной, содержащей представление списка, у вас есть фактическаясписок(массив) переменная, например:

var=(MICE foo MICE MICE bar MICE)

Тогда задача сводится к удалению определенных элементов из массива, что становится тривиальным с помощью оболочек с соответствующими переменными массива, такими как (откуда и взялся zshэтот синтаксис):var=(foo bar)

var=( ${var:#$word} )

Связанный контент