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