Просто зробіть:
case $1 in
(*:*) host=${1%:*} port=${1##*:};;
(*) host=$1 port=$default_port;;
esac
Можливо, ви захочете змінити case $1на, case ${1##*[]]}щоб урахувати значення $1типу [::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 вище)).
Цей оператор спліт-глобус перешкоджає та заподіює стільки шкоди в інший час, що, здавалося б, справедливо, що він буде використовуватися, коли це потрібно (хоча, я згоден, це дуже громіздко використовувати, особливо враховуючи, що 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, але потім зауважте, що єрести (або гередоки) додають додатковий символ нового рядка!)
- in
zsh(звідки походить синтаксис), і bashтут рядки реалізуються за допомогою тимчасових файлів, тому це, як правило, менш ефективно, ніж використання ${x#y}операторів або split + glob.