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

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周围没有括号,它可以工作。


当前回答

你可以在很多情况下应用awk

echo "bla@some.com;john@home.com"|awk -F';' '{printf "%s\n%s\n", $1, $2}'

你也可以用这个

echo "bla@some.com;john@home.com"|awk -F';' '{print $1,$2}' OFS="\n"

其他回答

取自Bash shell脚本拆分数组:

IN="bla@some.com;john@home.com"
arrIN=(${IN//;/ })
echo ${arrIN[1]}                  # Output: john@home.com

说明:

此构造将替换所有出现的“;”(首字母//表示全局替换)在字符串in中使用“”(单个空格),然后将空格分隔的字符串解释为数组(这就是周围的括号所做的)。

大括号内用于替换每个“;”的语法带有“”字符的字符称为参数扩展。

有一些常见的陷阱:

如果原始字符串有空格,则需要使用IFS:

IFS=“:”;arrIN=($IN);未设置IFS;

如果原始字符串包含空格,并且分隔符是新行,则可以使用以下命令设置IFS:

IFS=$'\n';arrIN=($IN);未设置IFS;

又一个迟来的答案。。。如果你对java有兴趣,这里是bashj(https://sourceforge.net/projects/bashj/)解决方案:

#!/usr/bin/bashj

#!java

private static String[] cuts;
private static int cnt=0;
public static void split(String words,String regexp) {cuts=words.split(regexp);}
public static String next() {return(cnt<cuts.length ? cuts[cnt++] : "null");}

#!bash

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

: j.split($IN,";")    # java method call

while true
do
    NAME=j.next()     # java method call
    if [ $NAME != null ] ; then echo $NAME ; else exit ; fi
done

这也适用于:

IN="bla@some.com;john@home.com"
echo ADD1=`echo $IN | cut -d \; -f 1`
echo ADD2=`echo $IN | cut -d \; -f 2`

小心,这个解决方案并不总是正确的。万一你通过了“bla@some.com“仅,它将分配给ADD1和ADD2。

两种都不需要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-)}

您可以设置内部字段分隔符(IFS)变量,然后让它解析为数组。当在命令中发生这种情况时,IFS的赋值只发生在单个命令的环境中(读取)。然后,它根据IFS变量值将输入解析为数组,然后我们可以对其进行迭代。

此示例将解析一行由;,将其推入阵列:

IFS=';' read -ra ADDR <<< "$IN"
for i in "${ADDR[@]}"; do
  # process "$i"
done

另一个示例用于处理$IN的整个内容,每次一行输入由;:

while IFS=';' read -ra ADDR; do
  for i in "${ADDR[@]}"; do
    # process "$i"
  done
done <<< "$IN"