Самый простой способ (для оболочек с <<<):
IFS='_' read -r a second a fourth a <<<"$string"
Использование временной переменной $ a
вместо $ _
, потому что одна оболочка жалуется.
В полном сценарии:
string='one_two_three_four_five'
IFS='_' read -r a second a fourth a <<<"$string"
echo "$second $fourth"
Нет изменения IFS, нет проблем с set -f
(расширение имени пути) Нет изменений в позиционных параметрах («$ @»).
Для решения, переносимого на все оболочки (да, включая все POSIX) без изменения IFS или set -f
, используйте (немного более сложный) эквивалент heredoc:
string='one_two_three_four_five'
IFS='_' read -r a second a fourth a <<-_EOF_
$string
_EOF_
echo "$second $fourth"
Поймите, что это решение (как здесь-документ, так и использование <<<
) удалит все завершающие символы новой строки.
И что это разработано для "однострочной" переменной content.
Решения для многострочных приложений возможны, но требуются более сложные конструкции.
Очень простое решение возможно в bash версии 4.4
readarray -d _ -t arr <<<"$string"
echo "array ${arr[1]} ${arr[3]}" # array numbers are zero based.
Для оболочек POSIX нет эквивалента, так как многие POSIX у оболочек нет массивов.
Для оболочек, которые имеют массивы, это может быть просто:
(проверено, работает в attsh, lksh, mksh, ksh и bash)
set -f; IFS=_; arr=($string)
Но с большим количеством дополнительных сантехнических работ, которые нужно сохранить и сбросить переменные и параметры:
string='one_* *_three_four_five'
case $- in
*f*) noglobset=true; ;;
*) noglobset=false;;
esac
oldIFS="$IFS"
set -f; IFS=_; arr=($string)
if $noglobset; then set -f; else set +f; fi
echo "two=${arr[1]} four=${arr[3]}"
В zsh массивы начинаются с 1 и по умолчанию не разделяют строку.
Поэтому необходимо внести некоторые изменения, чтобы это работало в zsh.