Просто делать:
case $1 in
(*:*) host=${1%:*} port=${1##*:};;
(*) host=$1 port=$default_port;;
esac
Возможно, вы захотите изменить на, case $1чтобы case ${1##*[]]}учесть значения $1like [::1](адрес IPv6 без части порта ).
Чтобы разделить, вы можете использовать оператор split + glob (оставить расширение параметра без кавычек), так как для этого он и нужен:
set -o noglob # disable glob part
IFS=: # split on colon
set -- $1 # split+glob
host=$1 port=${2:-$default_port}
(хотя это не позволит использовать имена хостов, содержащие двоеточие (как для этого адреса IPv6 выше)).
Этот оператор split + glob мешает и причиняет столько вреда в остальное время, что было бы совершенно справедливо использовать его всякий раз, когда это необходимо (хотя, я согласен, его очень громоздко использовать, особенно учитывая, что POSIX shне имеет поддержка локальной области видимости, ни для переменных ( $IFSздесь), ни для опций ( noglobздесь) (хотя ashи dashнекоторые производные, такие как (вместе с реализациями AT & T ksh, zshи bash4.4 и выше)).
Обратите внимание, что IFS=: read A B <<< "$1"есть несколько собственных проблем:
- Вы забыли,
-rчто означает, что обратная косая черта подвергнется специальной обработке.
- было бы разделить
[::1]:443на [и :1]:443вместо того , чтобы [и пустую строку (для которой вам нужно IFS=: read -r A B rest_ignoredили [::1]и 443(для которых вы не можете использовать этот подход)
- он удаляет все после первого вхождения символа новой строки, поэтому его нельзя использовать с произвольными строками (если только вы не используете
-d ''в zshили bashданные не содержат NUL-символов, но затем обратите внимание, что здесь-строки (или heredocs) действительно добавляют дополнительный символ новой строки!)
- в
zsh(откуда исходит синтаксис) и bashздесь строки реализуются с использованием временных файлов, поэтому обычно они менее эффективны, чем использование ${x#y}операторов split или glob.