
Как в 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 kshglob
zsh реализовать поддержку +([[:space:]])
оператора ksh88 для сопоставления одного или нескольких пробельных символов.
Или используя zsh
собственный extendedglob
s( 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} )