Bash массив оставить элементы, содержащие строку - PullRequest
4 голосов
/ 19 марта 2012

Я буду коротким, у меня есть

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

Я хочу это

array=( two.b four.b five_b_abc )

от здесь я нашел это

# 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 элементов, где мне нужно это сделать, мне нужно, чтобы он былкак можно быстрее с данными, поэтому, пожалуйста, не петли решения.

Ответы [ 3 ]

5 голосов
/ 19 марта 2012

Вы можете попробовать это:

array2=(`echo ${array[@]} | sed 's/ /\n/g' | grep b`)
5 голосов
/ 19 марта 2012

Редактировать: добавлено сравнение времени (в конце) и избавлено от tr

Можно заменить содержимое элементов массива, используя bash Расширение параметра , т.е. ${var[@]....} но вы не можете удалить элементы. Лучшее, что вы можете получить с расширением параметров, это сделать пустыми ("") те элементы, которые вам не нужны.

Вместо этого вы можете использовать printf, sed и IFS. Преимущество этого состоит в том, что вы можете использовать полный синтаксис регулярных выражений (а не только выражения глобализации оболочки) ... и это на намного быстрее, чем при использовании цикла ...

Этот пример оставляет элементы массива, которые содержат 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
========

Для общего ознакомления: тестирование массива, содержащего 10 тыс. Элементов. выбрав 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'))

1-й цикл метод:

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

2-й цикл метод:

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
0 голосов
/ 14 мая 2019

Если вы установите IFS равным $ '\ n', то вы можете использовать команду echo в массиве с символом '*' в качестве индекса, вместо printf с символом '@':

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

Индекс '*' объединяет элементы массива вместе, разделенные IFS. (Кстати, я только недавно узнал об этом сам.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...