我的dash
脚本采用 形式的参数hostname:port
,即:
myhost:1234
而端口是可选的,即:
myhost
我需要将主机和端口读取到单独的变量中。对于第一种情况,我可以这样做:
HOST=${1%%:*}
PORT=${1##*:}
但在第二种情况下,当端口被省略时,这不起作用;echo ${1##*:}
仅返回主机名,而不是空字符串。
在 Bash 中,我可以这样做:
IFS=: read A B <<< asdf:111
但这在dash
.
我可以:
在破折号中拆分字符串,而不调用外部程序(awk
、tr
等)吗?
答案1
做就是了:
case $1 in
(*:*) host=${1%:*} port=${1##*:};;
(*) host=$1 port=$default_port;;
esac
您可能需要更改 tocase $1
以case ${1##*[]]}
考虑$1
类似的值[::1]
(没有港口部分)。
要拆分,您可以使用分割+全局运算符(保留参数扩展不带引号),因为这就是它的用途:
set -o noglob # disable glob part
IFS=: # split on colon
set -- $1 # split+glob
host=$1 port=${2:-$default_port}
(尽管这不允许主机名包含冒号(如上面的 IPv6 地址))。
split+glob 运算符妨碍并造成如此大的伤害其余时间,只要需要就可以使用它,这似乎是公平的(不过,我同意使用起来非常麻烦,特别是考虑到 POSIXsh
不支持本地范围,既不支持变量($IFS
此处)也不支持选项) (noglob
此处)(尽管ash
和 类似的衍生物dash
是其中一些(以及ksh
、zsh
和bash
4.4 及以上版本的 AT&T 实现))。
请注意,它IFS=: read A B <<< "$1"
本身有一些问题:
- 您忘记了,
-r
这意味着反斜杠将经过一些特殊处理。 - 它会分成
[::1]:443
and[
而:1]:443
不是[
and 空字符串(为此您需要IFS=: read -r A B rest_ignored
or[::1]
and443
(为此您不能使用该方法) - 它会删除第一次出现换行符之后的所有内容,因此它不能与任意字符串一起使用(除非您
-d ''
在zsh
or中使用bash
并且数据不包含 NUL 字符,但请注意herestrings(或heredocs)确实添加了一个额外的换行符!) - in
zsh
(语法来源)和bash
,这里的字符串是使用临时文件实现的,因此它通常比使用${x#y}
或 split+glob 运算符效率低。
答案2
:
只需在单独的语句中删除;另外,从输入中删除 $host 以获取端口:
host=${1%:*}
port=${1#"$host"}
port=${port#:}
答案3
另一个想法:
host=${1%:*}
port=${1##*:}
[ "$port" = "$1" ] && port=''
答案4
这里字符串只是单行此处文档的语法快捷方式。
$ set myhost:1234
$ IFS=: read A B <<EOF
> $1
> EOF
$ echo "$A"
myhost
$ echo "B"
1234