Просто делать:
case $1 in
(*:*) host=${1%:*} port=${1##*:};;
(*) host=$1 port=$default_port;;
esac
Возможно, вы захотите изменить на, case $1
чтобы case ${1##*[]]}
учесть значения $1
like [::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
и bash
4.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.