如何在 Bash 中将 IFS 设置为两个字节值?
IFS=',;'
将分隔位于两个 simple,
和/或 simple之间的每个部分,;
而不是作为,;
分隔
符 如何模拟/解决方法,以便给出解决方案?之前谢谢
答案1
您可以切换到zsh
而不是bash
使用它的s
(用于s
plit)参数扩展标志:
$ string='foo,;bar,;,;baz'
$ words=("${(@s[,;])string}")
$ typeset -p words
typeset -a words=( foo bar '' baz )
请注意,这是分裂不是界定,foo,;
将被拆分为foo
和 空字符串,而不是foo
像bash
的 IFS 拆分那样(仅包含单个字符)。
另请注意,在bash
(和zsh
,但不是所有 shell)中,分词是在人物的$IFS
, 不字节。例如,使用IFS='é'
,Stéphane
将被拆分为St
甚至phane
在é
以两个字节编码的语言环境中(例如在字符映射为 UTF-8 的语言环境中,这是目前最常见的)。
答案2
bash(版本 4.3+)函数:
split() {
local string=$1 fs=$2
local -n fields=$3
fields=()
while [[ $string =~ (.*)"$fs"(.*) ]]; do
fields=( "${BASH_REMATCH[2]}" "${fields[@]}" )
string=${BASH_REMATCH[1]}
done
fields=( "$string" "${fields[@]}" )
}
用法:
$ string="field1,;field2,field2b,;field3a;field3b,;,;field4"
$ split "$string" ",;" result
$ declare -p result
declare -a result=([0]="field1" [1]="field2,field2b" [2]="field3a;field3b" [3]="" [4]="field4")
它会失败,就像许多实现 CSV 解析的天真的尝试一样,分隔符用引号引起来:
$ split 'Thoughtfully, he said "Hello, friend."' , x
$ declare -p x
declare -a x=([0]="Thoughtfully" [1]=" he said \"Hello" [2]=" friend.\"")
答案3
IFS
是一组单字符分隔符,因此 with IFS=,;
、;
或,
都将用作分隔符,并且a,b,;c;d
将有五个字段。如果您只想使用该组合,;
作为单个分隔符,则必须手动执行此操作。一种方法是用,;
您输入的某个单个字符替换该对IFS
:
s='a,b,;c;d'
IFS=#
fields=(${s//,;/#})
${s//,;/#}
将所有子字符串替换,;
为#
,然后不带引号的扩展拆分结果。现在数组fields
包含a,b
和c;d
。请注意,它还将使用生成的单词作为 glob(文件名通配符)。您可能希望使用set -f
/来防止这种情况set -o noglob
,但请注意,除了分配给 之外IFS
,它也具有全局效果。
或者你可以使用sed
,特别是如果你有一个管道开始:
sed -e 's/,;/#/g'