2

I have the following Array Loop set up. It simply loops through a string and checks to see if each item matches a letter and sets some variables accordingly.

#!/usr/bin/env bash
IN="ItemName -a -b"

itemA=0
itemB=0
itemI=0

while IFS=' -' read -ra ARR; do
    for x in "${ARR[@]}"; do
        echo "x = $x"
        y=${x:0:1}
        echo "y = $y"
        case $y in
            "a") itemA=1 ;;
            "b") itemB=1 ;;
            "I") itemI=1 ;;
        esac
    done
done <<< "$IN"

echo "itemA is $itemA
echo "itemB is $itemB"
echo "itemI is $itemI" 

However, for the first element ("itemName"), I need to set this separately, so that it isn't checked as part of the case stemement. Ideally I want to end up with:

itemName is ItemName
itemA is 1
itemB is 1
itemI is 0

How can I check for the first element? I tried

if [ ${ARR[0]} ] ; then
    itemName=$x
else
 . . . 
fi  

but ended up with none of the variables getting set.

4
  • Isn't itemI ItemName? just save x for itemI and return x instead of 0/1 for itemI if that's what you want. – Dani_l Dec 10 '15 at 12:25
  • This looks like a job for getopts. Also see the Small getopts tutorial. – PM 2Ring Dec 10 '15 at 12:48
  • cheers Dani_I, but if I have ItemName -a -b -I or AnotherItem -a -b then ItemI will be wrong. Is there simply a way of saying if this is the first item in an Array do this else do that? – IGGt Dec 10 '15 at 14:26
  • maybe it's me, but getopts looks overly complex for my needs, Plus I couldn't get it to work, but cheers anyway – IGGt Dec 10 '15 at 14:36
2

I don't see why you're using a while loop. Loose the while and your problems disappear:

#!/usr/bin/env bash
IN="ItemName -a -b"
itemA=0
itemB=0
itemI=0

## Read the array, no loop required
IFS=' -' read -ra ARR <<<"$IN"
## Save the 1st element as itemN
itemN=${ARR[0]}
## Remove itemN from the array
unset ARR[0]
## Now loop over the rest
for x in "${ARR[@]}"; do
    y=${x:0:1}
    case $y in
        "a") itemA=1 ;;
        "b") itemB=1 ;;
        "I") itemI=1 ;;
        esac
done

echo "itemN is $itemN"
echo "itemA is $itemA"
echo "itemB is $itemB"
echo "itemI is $itemI" 

Running the script above prints:

itemN is ItemName
itemA is 1
itemB is 1
itemI is 0
1
  • You are quite right, that is exactly what I was after, cheers. – IGGt Dec 10 '15 at 15:51
0

I don't know if this is necessarily the best way, but it works:

#!/usr/bin/env bash
IN="ItemName -a -b"

itemName=0
itemA=0
itemB=0
itemI=0

while IFS=' -' read -ra ARR; do
    for x in "${ARR[@]:1:0}"; do
        itemName=$x
    done

    for x in "${ARR[@]:1}"; do
        y=${x:0:1}
        case $y in
            "a") itemA=1 ;;
            "b") itemB=1 ;;
            "I") itemI=1 ;;
        esac
    done
done <<< "$IN"

echo "itemName is $itemName"
echo "itemA is $itemA
echo "itemB is $itemB"
echo "itemI is $itemI" 

Basically, I processed the Array twice. Once to get just the first Item, and then again to get all items except the first item.

0

I would use more arrays. This answer relies on bash version 4 for associative arrays.

IFS=' -' read -ra words <<<"$IN"
declare -A items

for i in "${words[@]}"; do
    [[ $i == "ItemName" ]] && continue
    items["${i:0:1}"]=1
done

for key in "${!items[@]}"; do
    echo "item $key is ${items[$key]}"
done
item a is 1
item b is 1

If you need to set some default values for the items array:

declare -A items=([a]=0 [b]=0 [c]=0)

Then you would see

item a is 1
item b is 1
item c is 0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.