bash数组保留包含字符串的元素

nkv*_*nkv 4 arrays bash element conditional-statements

我会很简短,我拥有的是什么

array=( one.a two.b tree.c four.b five_b_abc)
Run Code Online (Sandbox Code Playgroud)

我要这个

array=( two.b four.b five_b_abc )
Run Code Online (Sandbox Code Playgroud)

这里 我发现了这个

# replace any array item matching "b*" with "foo"
array=( foo bar baz )
array=( "${array[@]/%b*/foo}" )
echo "${orig[@]}"$'\n'"${array[@]}"
Run Code Online (Sandbox Code Playgroud)

怎么这不起作用

array2=( ${array[@]//%^.p/})
Run Code Online (Sandbox Code Playgroud)

结果 array2=array

这会删除所有p

array2=(${array[@]/*p*/})
Run Code Online (Sandbox Code Playgroud)

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

我需要一个想法如何添加^ p(所有接受p),并得到我的解决方案

array2=(${array[@]/*^p*/}
Run Code Online (Sandbox Code Playgroud)

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

Pet*_*r.O 5

编辑:添加时间比较(结束时)并摆脱了 tr

可以使用bash 参数扩展替换数组元素的内容,即.但你实际上不能删除元素.参数扩展可以获得的最好效果是使那些你不想要的元素为null(""). ${var[@]....}

相反,你可以使用printfsed,和IFS.这有利于你使用完整的正则表达式语法(不仅仅是shell globbing表达式)...而且它比使用循环快得多......

这个例子留下了包含的数组元素c
注意:这个方法适合数据中的空格.这是通过IFS=\n

IFS=$'\n'; a=($(printf '%s\n' "${a[@]}" |sed '/c/!d'))
Run Code Online (Sandbox Code Playgroud)

这里再次使用转储之前/之后:

#!/bin/bash

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

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

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

输出:

======== 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
========
Run Code Online (Sandbox Code Playgroud)

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

a=( a\ \ \ \ b{0..9999} )
Run Code Online (Sandbox Code Playgroud)

 printf方法采用:( 0m0.226s得到顺序索引值)
    第一个循环方法:( 0m4.007s它在索引值中留下间隙)
第二个循环方法:( 0m7.862s得到顺序索引值)

printf方法:

IFS=$'\n'; a=($(printf '%s\n' "${a[@]}" |sed '/.*[5-9]...$/!d'))
Run Code Online (Sandbox Code Playgroud)

第一循环方法:

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

第二循环方法:

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
Run Code Online (Sandbox Code Playgroud)


kev*_*kev 5

您可以尝试以下方法:

array2=(`echo ${array[@]} | sed 's/ /\n/g' | grep b`)
Run Code Online (Sandbox Code Playgroud)