Reputation: 364
I have a bash script which loops through a list of arrays by 2 at a time, like this;
#!/bin/bash
declare -a arr=(
"apple" "fruit"
"lettuce" "vegetables"
"almonds" "nuts"
)
for ((i=0; i<${#arr[@]}; i+=2)); do
echo "${arr[i]} ${arr[i+1]}"
done
and when you run this script, it prints out;
apple fruit
lettuce vegetables
almonds nuts
I'm looking for a way to select a specific item from the array and only print that one, something like this;
./script.sh apple
and it will print out only the apple and the 2nd item with the apple;
apple fruit
or it can be the other way, like; ./script.sh fruit
and it will print out;
apple fruit
and if no arguments given, just print out everything.
So I'm basically looking for a way to choose items from the array, is this possible to do with bash arrays?
Upvotes: 0
Views: 440
Reputation: 84607
With the addition of a simple test to ensure you are (1) not matching the last element and (2) the current element equals the input parameter, you can output the current and next elements in the array with:
updated to output all if no positional parameter provided
#!/bin/bash
declare -a arr=(
"apple" "fruit"
"lettuce" "vegetables"
"almonds" "nuts"
)
declare -i nelem=${#arr[@]}
for ((i = 0; i< nelem; i++)); do
if [ -z "$1" ]; then ## no argument given - output all
echo "${arr[i]}"
else
## test not last element and current equals input
[ "$i" -lt $((nelem - 1)) ] && [ "${arr[i]}" = "$1" ] &&
echo "${arr[i]} ${arr[$((i+1))]}"
fi
done
Example Use/Output
$ bash a.sh apple
apple fruit
$ bash a.sh lettuce
lettuce vegetables
$ bash a.sh almonds
almonds nuts
$ bash a.sh nuts
(no output)
No input case:
$ bash a.sh
apple
fruit
lettuce
vegetables
almonds
nuts
Look things over and let me know if you have further questions.
Upvotes: 1
Reputation: 295696
First, as the simplest possible thing, taking your exact existing logic and just adding a conditional around the print operation:
#!/bin/bash
declare -a arr=(
"apple" "fruit"
"lettuce" "vegetables"
"almonds" "nuts"
)
for ((i=0; i<${#arr[@]}; i+=2)); do
if [[ ${arr[i]} = "$1" ]] || [[ ${arr[i+1]} = "$2" ]]; then
echo "${arr[i]} ${arr[i+1]}"
fi
done
However, if in your real-world use case you're going to be doing several invocations within the same script, it'll be worth the overhead to build a lookup table:
# initial setup, only needs to happen once
declare -a arr=(
"apple" "fruit"
"lettuce" "vegetables"
"almonds" "nuts"
)
declare -A arrayFwd arrayRev
for ((i=0; i<${#arr[@]}; i+=2)); do
arrayFwd[${arr[i]}]=${arr[i+1]}
arrayRev[${arr[i+1]}]=${arr[i]}
done
lookup() {
if [[ ${arrayFwd[$1]} ]]; then
echo "$1 ${arrayFwd[$1]}"
elif [[ ${arrayRev[$1]} ]]; then
echo "${arrayRev[$1]} $1"
fi
}
...after which you can cheaply run:
lookup apple
or
lookup fruit
...and performance will be identical no matter how many items are in the lookup table.
Upvotes: 3