Bash 使用子字符串进行字符操作非常昂贵。选择是痛苦的。有什么建议吗?

Bash 使用子字符串进行字符操作非常昂贵。选择是痛苦的。有什么建议吗?,bash,substring,Bash,Substring,我有一个算法,需要对非常大的字符串进行字符级操作。事实证明,bash子字符串机制c=${string:$curchar:1}非常昂贵,其成本似乎随着字符串的长度而增加。测试表明,将非常大的字符串复制到字符数组并对其进行操作是值得的。考虑下面的代码,它使用一个嵌套循环中的每个方法访问一个大字符串,以显示慢访问对算法的影响。p> #!/bin/bash array() { curchar=0 while read -n 1 c ; do chars[$cur

我有一个算法,需要对非常大的字符串进行字符级操作。事实证明,bash子字符串机制c=${string:$curchar:1}非常昂贵,其成本似乎随着字符串的长度而增加。测试表明,将非常大的字符串复制到字符数组并对其进行操作是值得的。考虑下面的代码,它使用一个嵌套循环中的每个方法访问一个大字符串,以显示慢访问对算法的影响。p>
#!/bin/bash
array() 
{
    curchar=0
    while read -n 1 c ; do
            chars[$curchar]="$c"
            curchar=$((curchar+1))
    done <<< "$1"

    len=$curchar
    while [ $len -gt 0 ] ; do
            curchar=0
            while [ $curchar -lt $len ] ; do
                    c="${chars[$curchar]}"
                    printf "[%c]" "$c"
                    curchar=$((curchar + 1))
            done    
            len=$((len / 2 ))
            printf "\n"
    done    

}        
string()
{
    len="${#1}"
    while [ $len -gt 0 ] ; do
            curchar=0
            while [ $curchar -lt $len ] ; do
                    c=${1:$curchar:1}
                    printf "[%c]" "$c"
                    curchar=$((curchar + 1))
            done    
            len=$((len / 2 ))
            printf "\n"
    done    
}

usecut()
{
    len="${#1}"
    while [ $len -gt 0 ] ; do
            curchar=1
            while [ $curchar -le $len ] ; do
                    c=$(echo $1 | cut -c "$curchar")
                    printf "[%c]" "$c"
                    curchar=$((curchar + 1))
            done    
            len=$((len / 2 ))
            printf "\n"
    done    
}

$1 "$(cat $2)"      # call one of these with a passed string

不用说,必须构建字符数组,特别是考虑到字符串肯定已经存在于底层系统中,这是一件痛苦的事情。有没有更好的方法可以直接有效地访问字符串?

如果您在bash中进行字符串处理,至少要注意一点,bash是区域设置感知的;在具有多字节字符串表示(如UTF-8)的区域设置中,bash将基于字符而不是字节计算长度和子字符串索引

如果您喜欢字节计数,可以通过将locale设置为C来大大加快速度。在我的测试中,它似乎将长度和子字符串扩展的速度提高了一倍


然而,对于大型字符串来说,这仍然是缓慢的;bash根本不是为了成为一种高效的通用编程语言而设计的。它会进行大量的字符串复制,但与进程分叉相比,这种开销通常可以忽略不计。但是,如果您使用的是多兆字节的字符串,您会注意到它的速度很慢,唯一合理的建议是使用一种针对您现有的用例进行了更好优化的语言。

如果您在bash中进行字符串处理,您至少应该注意一件事,即bash是区域设置感知的;在具有多字节字符串表示(如UTF-8)的区域设置中,bash将基于字符而不是字节计算长度和子字符串索引

如果您喜欢字节计数,可以通过将locale设置为C来大大加快速度。在我的测试中,它似乎将长度和子字符串扩展的速度提高了一倍


然而,对于大型字符串来说,这仍然是缓慢的;bash根本不是为了成为一种高效的通用编程语言而设计的。它会进行大量的字符串复制,但与进程分叉相比,这种开销通常可以忽略不计。但是,如果您使用的是多兆字节字符串,您会注意到它的速度很慢,唯一可行的建议是使用一种更适合您的用例的语言。

您可以使用cut-c您能更具体一些吗?我看不出如何不涉及昂贵的子壳。字符串太长,不能作为参数,因此必须通过管道将其传输到子shell:`c=$echo$1 | cut-c$curchar`这确实比子字符串快得多,但仍然很慢:$time./substring_very_pricine.sh usecut longline>/dev/null real 1m45.809s user 1m19.733s sys 0m25.026sg好东西!但我想折衷的办法是,如果你想要快速处理,你必须做痛苦的编码。该字符串必须已在基础系统中。。。我想这就是c/系统编程的意义所在。cat$2表示您正在从文件中读取字符串。shell将把该值存储在其可用的资源中。1.其环境,。文件系统3,tmp存储(即管道)。12K字符串上的子字符串小如您所说,您真正需要的大小是多少?似乎是一个6西格玛用例。祝你好运抱歉-我的想法是c=$echo$1 | cut-c$curchar`。如果shell操作太慢,那么可能是时候考虑升级到另一种脚本语言awk或perl等,或者升级到C或其他程序了。祝你好运@user3546411:bash从未打算用作通用编程语言,并且它也没有针对此类用途进行优化。处理大字符串会很慢。如果您对大型字符串有复杂的计算,请使用针对该用例优化的语言?我看不出如何不涉及昂贵的子壳。字符串太长,不能作为参数,因此必须通过管道将其传输到子shell:`c=$echo$1 | cut-c$curchar`这确实比子字符串快得多,但仍然很慢:$time./substring_very_pricine.sh usecut longline>/dev/null real 1m45.809s user 1m19.733s sys 0m25.026sg好东西!但我想折衷的办法是,如果你想要快速处理,你必须做痛苦的编码。该字符串必须已在基础系统中。。。我想这就是c/系统编程的意义所在。cat$2表示您正在从文件中读取字符串。shell将把该值存储在其可用的资源中。1.其环境,。文件系统3,tmp存储(即管道)。12K字符串上的子字符串小如您所说,您真正需要的大小是多少?似乎是一个6西格玛用例。祝你好运抱歉-我的想法是c=$echo$1 | cut-c$cur
char`。如果shell操作太慢,那么可能是时候考虑升级到另一种脚本语言awk或perl等,或者升级到C或其他程序了。祝你好运@user3546411:bash从未打算用作通用编程语言,并且它也没有针对此类用途进行优化。处理大字符串会很慢。如果您在大型字符串上有复杂的计算,请使用针对该用例优化的语言。
$ time ./substring_very_expensive.sh array longline > /dev/null

real    0m0.653s
user    0m0.644s
sys     0m0.006s
$ time ./substring_very_expensive.sh string longline > /dev/null

real    0m16.427s
user    0m16.401s
sys     0m0.019s
$time ./substring_very_expensive.sh usecut longline > /dev/null

real    1m45.809s
user    1m19.733s
sys     0m25.026s