我将此字符串存储在变量中:
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:
awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]\n", $i)}' <<< "$IN"
这将字段分隔符设置为;,以便它可以用for循环遍历字段并相应地打印。
Test
$ IN="bla@some.com;john@home.com"
$ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]\n", $i)}' <<< "$IN"
> [bla@some.com]
> [john@home.com]
使用另一个输入:
$ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]\n", $i)}' <<< "a;b;c d;e_;f"
> [a]
> [b]
> [c d]
> [e_]
> [f]
以下Bash/zsh函数将其第一个参数拆分为第二个参数给出的分隔符:
split() {
local string="$1"
local delimiter="$2"
if [ -n "$string" ]; then
local part
while read -d "$delimiter" part; do
echo $part
done <<< "$string"
echo $part
fi
}
例如,命令
$ split 'a;b;c' ';'
产量
a
b
c
例如,该输出可以通过管道传输到其他命令。例子:
$ split 'a;b;c' ';' | cat -n
1 a
2 b
3 c
与给出的其他解决方案相比,该解决方案具有以下优点:
IFS没有被覆盖:由于甚至局部变量的动态作用域,在循环上覆盖IFS会导致新值泄漏到从循环内执行的函数调用中。不使用数组:使用read将字符串读入数组需要Bash中的-a标志和zsh中的-a标志。
如果需要,可以将函数放入脚本,如下所示:
#!/usr/bin/env bash
split() {
# ...
}
split "$@"
我看到了一些引用cut命令的答案,但它们都被删除了。有点奇怪的是,没有人详细阐述过这一点,因为我认为这是执行这类任务更有用的命令之一,尤其是用于解析分隔的日志文件。
在将这个特定示例拆分为bash脚本数组的情况下,tr可能效率更高,但可以使用cut,如果您想从中间拉取特定字段,则更有效。
例子:
$ echo "bla@some.com;john@home.com" | cut -d ";" -f 1
bla@some.com
$ echo "bla@some.com;john@home.com" | cut -d ";" -f 2
john@home.com
显然,您可以将其放入一个循环中,并迭代-f参数以独立拉动每个字段。
当您有一个分隔的日志文件,其中包含如下行时,这会更有用:
2015-04-27|12345|some action|an attribute|meta data
cut非常方便,能够抓取这个文件并选择一个特定的字段进行进一步处理。