tags:

views:

302

answers:

4

Hello. I'd like to change the value of an array and would appreciate any help.

I got an array like this:

users=(root isometric akau)

(This is actually a list of current users) that I'd like to be able to test if the user exists and if they do not, then to remove the person from the array. I've tried experiment with this by putting it in a for loop and evaluating it:

for i in ${users[@]}; do
  eval "users=($([ -z $(grep \"^\$i\" /etc/shadow) ] && sed \"s/\$i//g\"))"
done

echo $users

I thought about playing with this some more but I thought I might be getting too complicated (I'm not sure I can put a command in an array). Anyone have an idea on how to do this?

Edit:

How I entered the array variable unset number:

cnt=0
for i in ${users[@]}; do
  [ -z "$(grep "^$i" /etc/shadow)" ] && unset users[cnt] || ((cnt++))
done

Edit2:

Actually Dennis's is even better.

A: 

If you want to remove jane from users:

users=(john joe mary jane liz root foobar)

for ((i = 0; i < ${#users[@]}; ++i)); do
    [[ ${users[i]} == jane ]] && break
done

users=(${users[@]:0:i} ${users[@]:i+1})

echo "${users[@]}" #=> john joe mary liz root foobar

The general principle is that there is no array slice in bash (obviously); you have to recreate the array without the excluded element(s).

That said, there are numerous ways to do what your are looking for in a for(in) loop.

guns
+2  A: 

So if you have...

$ users=(root isometric akau)
$ echo ${users[*]}
root isometric akau

All you need to do is, say:

$ unset users[1]

And then...

$ echo ${users[*]}
root akau
$
DigitalRoss
Haha, nice. Much better. Thanks DR. Just for reference, I'll put how to discover the number of the of the array value in the original post.
Todd Partridge
A: 
users=(root nobody akau)
declare -a shadowusers
declare -a notinshadow
i=0
while IFS=":" read -r user b c d e f g h
do
    shadowusers[$i]=$user
    i=$((i+1))
done < "/etc/shadow"
for u in ${users[@]}
do
    found=0
    for s in ${shadowusers[@]}
    do
           case "$u" in
               "$s") found=1;;
           esac   
    done
    [ "$found" -eq 0 ] && notinshadow[$j]=$u
    j=$((j+1)) 
done 
echo ${notinshadow[@]}
+1 for creativity. Never thought to redirect to a while loop before... huh.
Todd Partridge
+2  A: 

You may not need a for loop. Try this:

users=(root isometric akau)
list="${users[@]/%/|}"      # convert array to list, add pipe char after each user
# strip the spaces from the list and look for usernames between the beg. of the line
# and the end of the word, make an array out of the result
users=($(grep -Eo "^(${list// })\>" /etc/shadow))

The grep, unraveled, would look like this:

grep -Eo "^(root|isometric|akau|)\>" /etc/shadow
Dennis Williamson
Very clever. I'd give it plus 2 for ingenuity if at all possible. Thank you.
Todd Partridge
The more I look at this, this is really good. wow
Todd Partridge