9

Given the following array in Shell Programming

foo=(spi spid spider spiderman bar lospia)

I would like to use GREP to search for all words in the array which has the 3 letters spi

Correct output : spi spi spider spiderman lospia

I have tried something like this

foo=(spi spid spider spiderman)

grep "spi" foo

But it seems it is wrong , what is the correct way to go about it ???

4 Answers 4

22

The simplest solution would be to pipe the array elements into grep:

printf -- '%s\n' "${foo[@]}" | grep spi

A couple of notes:

printf is a bash builtin, and you can look it up with man printf. The -- option tells printf that whatever follows is not a command line option. That guards you from having strings in the foo array being interpreted as such.

The notation of "${foo[@]}" expands all the elements of the array as standalone arguments. Overall the words in the array are put into a multi-line string and are piped into grep, which matches every individual line against spi.

Sign up to request clarification or add additional context in comments.

3 Comments

It may worth to translate it back into an array bar=$(printf -- '%s\n' "${foo[@]}" | grep spi | tr '\n' ' ');
Definitely the most helpful answer here. Substantially more efficient than bash for entry in "${foo[@]}"; do if echo "$entry" | grep spi &>/dev/null; then results+=("$entry") fi done which is what I had originally. Doing this instead improved performance by orders of magnitude: bash results+=($(printf "%s\n" "${foo[@]}" | grep spi))
what about using NUL bytes as array delimiters instead of spaces or newlines? some of my array data contains both and it's causing issues.
3

The following will print out all words that contain spi:

foo=(spi spid spider spiderman bar)
for i in ${foo[*]}
do
    echo $i | grep "spi"
done

Comments

2
IFS=$'\n' ; echo "${foo[*]}" | grep spi

This produces the output:

spi
spid
spider
spiderman
lospia

Comments

0

If the requirement is to run the script/extract under the exit-on-error shell flag ('-e') and unnecessarily exiting the script/extract whilst also avoiding the tedium of wrapping the code in "set +e" … "set -e", I always use case since unlike grep(1) or test(1), it (case) doesn't update $? …

for f in "${foo[@]}" ; do 
    case "$f" in
        *spi*) echo $f ;;
    esac
done

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.