我将此字符串存储在变量中:

IN="bla@some.com;john@home.com"

现在,我想将字符串拆分为:;分隔符,以便我可以:

ADDR1="bla@some.com"
ADDR2="john@home.com"

我不一定需要ADDR1和ADDR2变量。如果它们是数组的元素,那就更好了。


根据以下答案的建议,我最终得出了以下结论,这就是我想要的:

#!/usr/bin/env bash

IN="bla@some.com;john@home.com"

mails=$(echo $IN | tr ";" "\n")

for addr in $mails
do
    echo "> [$addr]"
done

输出:

> [bla@some.com]
> [john@home.com]

有一个解决方案涉及将Internal_field_separator(IFS)设置为;。我不确定这个答案发生了什么,如何将IFS重置为默认值?

回复:IFS解决方案,我尝试了这个,它奏效了,我保留了旧的IFS,然后恢复它:

IN="bla@some.com;john@home.com"

OIFS=$IFS
IFS=';'
mails2=$IN
for x in $mails2
do
    echo "> [$x]"
done

IFS=$OIFS

顺便说一下,当我尝试

mails2=($IN)

在循环中打印时,我只得到了第一个字符串,$in周围没有括号,它可以工作。


当前回答

如果您不使用数组,那么这一行如何:

IFS=';' read ADDR1 ADDR2 <<<$IN

其他回答

也许不是最优雅的解决方案,但可以使用*和空格:

IN="bla@so me.com;*;john@home.com"
for i in `delims=${IN//[^;]}; seq 1 $((${#delims} + 1))`
do
   echo "> [`echo $IN | cut -d';' -f$i`]"
done

输出

> [bla@so me.com]
> [*]
> [john@home.com]

其他示例(开头和结尾的分隔符):

IN=";bla@so me.com;*;john@home.com;"
> []
> [bla@so me.com]
> [*]
> [john@home.com]
> []

基本上,它会删除除以下字符以外的所有字符:;制作熟食;;;。然后,它执行从1到${#delims}计数的分隔符数的循环。最后一步是使用切割安全地获得$i部分。

这是我的答案!

DELIMITER_VAL='='

read -d '' F_ABOUT_DISTRO_R <<"EOF"
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.4 LTS"
NAME="Ubuntu"
VERSION="14.04.4 LTS, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 14.04.4 LTS"
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
EOF

SPLIT_NOW=$(awk -F$DELIMITER_VAL '{for(i=1;i<=NF;i++){printf "%s\n", $i}}' <<<"${F_ABOUT_DISTRO_R}")
while read -r line; do
   SPLIT+=("$line")
done <<< "$SPLIT_NOW"
for i in "${SPLIT[@]}"; do
    echo "$i"
done

为什么这种方法对我来说是“最好的”?

由于两个原因:

您不需要转义分隔符;空格不会有问题。该值将在数组中正确分隔。

IN="bla@some.com;john@home.com"
IFS=';'
read -a IN_arr <<< "${IN}"
for entry in "${IN_arr[@]}"
do
    echo $entry
done

输出

bla@some.com
john@home.com

系统:Ubuntu 12.04.1

两种都不需要bash数组的伯尔尼式替代方案:

案例1:保持简洁:使用NewLine作为记录分隔符。。。如。

IN="bla@some.com
john@home.com"

while read i; do
  # process "$i" ... eg.
    echo "[email:$i]"
done <<< "$IN"

注意:在第一种情况下,没有分支子进程来帮助列表操作。

想法:也许值得在内部广泛使用NL,在外部生成最终结果时只转换为不同的RS。

案例2:使用“;”作为记录分隔符。。。如。

NL="
" IRS=";" ORS=";"

conv_IRS() {
  exec tr "$1" "$NL"
}

conv_ORS() {
  exec tr "$NL" "$1"
}

IN="bla@some.com;john@home.com"
IN="$(conv_IRS ";" <<< "$IN")"

while read i; do
  # process "$i" ... eg.
    echo -n "[email:$i]$ORS"
done <<< "$IN"

在这两种情况下,子列表都可以在循环中组成。循环完成后,子列表是持久的。这在处理内存中的列表时非常有用,而不是将列表存储在文件中。{请保持冷静,继续进行B-)}

如果您不介意立即处理它们,我喜欢这样做:

for i in $(echo $IN | tr ";" "\n")
do
  # process
done

您可以使用这种循环来初始化数组,但可能有一种更简单的方法。