【问题标题】:bash array leave elements containing stringbash数组保留包含字符串的元素
【发布时间】:2012-04-03 11:31:54
【问题描述】:

我会很矮,我有的是

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[@]}"$'\n'"${array[@]}"

这怎么行不通

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

结果array2=array

这会删除所有带 p 的内容

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

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

我需要知道如何添加 ^p(都接受 p),并获得我的解决方案

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

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

【问题讨论】:

    标签: arrays bash element conditional-statements


    【解决方案1】:

    编辑:添加了时间比较(最后)并去掉了tr

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

    相反,您可以使用printfsedIFS。这样做的好处是允许您使用完整的正则表达式语法(而不仅仅是 shell 通配表达式)......而且它比使用循环快 很多......

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

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

    这里又是之前/之后的转储:

    #!/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 "========"
    

    输出:

    ======== 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=$'\n'; a=($(printf '%s\n' "${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
    

    【讨论】:

    • 我也要感谢你。 ypu 添加的网站从现在开始在我的书签中。
    【解决方案2】:

    你可以试试这个:

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

    【讨论】:

    【解决方案3】:

    如果您将 IFS 设置为 $'\n',那么您可以在数组上使用 echo 命令并以 '*' 作为下标,而不是使用带有 '@' 的 printf:

    IFS=$'\n'; a=($(echo "${a[*]}" | sed '/.*[5-9]...$/!d'))
    

    “*”下标将数组元素连接在一起,由 IFS 分隔。 (顺便说一下,我自己最近才知道这一点。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-13
      • 1970-01-01
      • 2013-06-02
      • 2013-11-06
      • 2012-09-01
      • 1970-01-01
      相关资源
      最近更新 更多