Bash数组留下包含字符串的元素

人气:809 发布:2022-10-16 标签: arrays bash element conditional-statements

问题描述

我会很短,我所拥有的是

array=( one.a two.b tree.c four.b five_b_abc)

我想要这个

array=( two.b four.b five_b_abc )

从here我找到了这个

# replace any array item matching "b*" with "foo"
array=( foo bar baz )
array=( "${array[@]/%b*/foo}" )
echo "${orig[@]}"$'
'"${array[@]}"

这怎么也不管用

array2=( ${array[@]//%^.p/})

结果array2=array

这将删除所有带有p的

array2=(${array[@]/*p*/})

结果array2=( one.a tree.c )

我需要知道如何添加^p(全部接受p),然后得到我的解决方案

array2=(${array[@]/*^p*/}

这是一个相当大的数组,大约10k个元素,我需要这样做,我需要尽可能快地处理数据,所以请不要使用循环解决方案。

推荐答案

编辑:添加了计时比较(结尾),删除了tr

可以使用bashParameter expansion替换数组元素的内容,即。${var[@]....}但您无法实际删除元素。使用参数扩展所能得到的最好结果是将不需要的元素设为空("")。

相反,您可以使用printfsedIFS。这样做的好处是允许您使用完整的正则表达式语法(不仅仅是外壳全局表达式)……而且它比使用循环快得多……

此示例留下包含c的数组元素 注意:此方法适用于数据中的空格。这是通过IFS=

实现的
IFS=$'
'; a=($(printf '%s
' "${a[@]}" |sed '/c/!d'))

这又是之前/之后转储:

#!/bin/bash

a=(one.ac two.b tree.c four.b "five b abcdefg" )

echo "======== Original array ===="
printf '%s
' "${a[@]}"

echo "======== Array containing only the matched elements 'c' ===="
IFS=$'
'; a=($(printf '%s
' "${a[@]}" |sed '/c/!d'))
printf '%s
' "${a[@]}"
echo "========"

输出:

======== Original array ====
one.ac
two.b
tree.c
four.b
five b abcdefg
======== Array containing only the matched elements 'c' ====
one.ac
tree.c
five b abcdefg
========

一般参考:测试包含10k元素的数组。选择5k:

a=( a    b{0..9999} )

当printf方法采用:0m0.226s(生成顺序索引值) 使用第一个循环方法:0m4.007s(在索引值上留下空白) 第二个循环方法:0m7.862s(生成顺序索引值)

printf方法:

IFS=$'
'; a=($(printf '%s
' "${a[@]}" |sed '/.*[5-9]...$/!d'))

第一循环方式:

iz=${#a[@]}; j=0
for ((i=0; i<iz; i++)) ;do
    [[ ! "${a[i]}" =~ .*[5-9]...$ ]] && unset a[$i]
done

第二循环方式:

iz=${#a[@]}; j=0
for ((i=0; i<iz; i++)) ;do
    if [[ ! "${a[i]}" =~ .*[5-9]...$ ]] ;then
        unset a[$i]
    else 
        a[$j]="${a[i]}=$i=$j"; ((j!=i)) && unset a[$i]; ((j+=1)); 
    fi
done

612