私のdash
スクリプトは、hostname:port
の形式のパラメーターを受け取ります。つまり、
myhost:1234
一方、ポートはオプションです。
myhost
ホストとポートを別々の変数に読み込む必要があります。最初のケースでは、私は行うことができます:
Host=${1%%:*}
PORT=${1##*:}
しかし、ポートが省略されている場合、それは2番目のケースでは機能しません。 echo ${1##*:}
は、空の文字列ではなく、単にホスト名を返します。
バッシュでは、私はできる:
IFS=: read A B <<< asdf:111
しかし、それはdash
では機能しません。
外部プログラム(awk
、tr
など)を呼び出さずに、:
の文字列をダッシュで分割できますか?
ただやる:
case $1 in
(*:*) Host=${1%:*} port=${1##*:};;
(*) Host=$1 port=$default_port;;
esac
case $1
のようなcase ${1##*[]]}
の値に対応するために$1
を[::1]
に変更したい場合があります(port部分)。
分割するには、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
のような派生物は、いくつかの派生物です(ksh
、zsh
およびbash
4.4以上のAT&T実装とともに))。
IFS=: read A B <<< "$1"
にはいくつかの問題があることに注意してください。
-r
を忘れた場合は、バックスラッシュが特別な処理を受けることを意味します。[::1]:443
と空の文字列([
または:1]:443
が必要な場合)の代わりに、[
をIFS=: read -r A B rest_ignored
と[::1]
に分割します。 443
(その方法は使用できません)zsh
またはbash
で-d ''
を使用し、データがtにはNUL文字が含まれていますが、ここでherestrings(またはheredocs)が余分な改行文字を追加することに注意してください!)zsh
(構文の由来)とbash
では、ここで文字列は一時ファイルを使用して実装されるため、${x#y}
またはsplit + glob演算子を使用するよりも一般的に効率がよくありません。別のステートメントで:
を削除するだけです。また、入力から$ Hostを削除してポートを取得します。
Host=${1%:*}
port=${1#"$Host"}
port=${port#:}
別の考え:
Host=${1%:*}
port=${1##*:}
[ "$port" = "$1" ] && port=''
Here文字列は、1行のhereドキュメントの構文上のショートカットにすぎません。
$ set myhost:1234
$ IFS=: read A B <<EOF
> $1
> EOF
$ echo "$A"
myhost
$ echo "B"
1234