0

I am adding elements on an array (Add a new element to an array without specifying the index in Bash) but I am getting an unexpected result. I suppose I am doing something wrong when adding elements in the array and/or when iterating the array to print its values.

Code:

for name in $(cat list.txt); do
    host $name.$DOMAIN | grep "has address" | cut -d" " -f4
done

for name in $(cat list.txt); do
    echo "."
    IPS+=(`host $name.$DOMAIN | grep "has address" | cut -d" " -f4`)
    echo ${#IPS[@]}
done

for ip in $IPS; do
    echo "IP: $ip"
done

Output:

12.210.145.45
67.20.71.219
75.58.197.10
31.70.88.22
.
1
.
3
.
4
.
4
.
4
IP: 12.210.145.45

Expected output:

Output:

12.210.145.45
67.20.71.219
75.58.197.10
31.70.88.22
.
1
.
2
.
3
.
4
IP: 12.210.145.45
IP: 67.20.71.219
IP: 75.58.197.10
IP: 31.70.88.22
user1156544
  • 1,725
  • 2
  • 25
  • 51
  • 1
    See [DontReadLinesWithFor](http://mywiki.wooledge.org/DontReadLinesWithFor) re: the `for ip in $(cat ...)` idiom, and also the related [BashPitfalls #1](http://mywiki.wooledge.org/BashPitfalls#for_f_in_.24.28ls_.2A.mp3.29). – Charles Duffy Aug 03 '18 at 17:21
  • Similarly, `addr=$(host "$name.$DOMAIN" | grep "has address" | cut -d" " -f4)"; if [[ $addr ]]; then ips+=( "$addr" ); fi` would be more reliable. (Does assume you fix your variable case, but that's a thing you should do). – Charles Duffy Aug 03 '18 at 17:22
  • 1
    That said, replacing `host` with `dig +short` would make this whole thing a lot simpler; do that and you don't need to mess with `grep` or `cut` at all. – Charles Duffy Aug 03 '18 at 17:23
  • Very interesting. Thanks for the pointer – user1156544 Aug 03 '18 at 17:34

1 Answers1

1

To iterate over an array, use

for ip in "${IPS[@]}" ; do

See PARAMETERS in man bash.

choroba
  • 231,213
  • 25
  • 204
  • 289
  • Great thanks. Is there a reason why the logged "." is appearing more than 4 times? including the logged size as: 1, 3, 4, 4 instead of the expected 1,2,3,4. – user1156544 Aug 03 '18 at 17:13
  • maybe `host $name.$DOMAIN | grep "has address" | cut -d" " -f4` returns more than one word? – choroba Aug 03 '18 at 17:14
  • `printf 'IP: %s\n' "${array[@]}"` is much shorter. – Charles Duffy Aug 03 '18 at 17:20
  • 1
    This line must be failing to add to the list: `IPS+=(\`host $name.$DOMAIN | grep "has address" | cut -d" " -f4\`)`. If list.txt has 4 lines of input and one of the lines has a space in it, you are going to loop 5 times. Try adding `echo "$name"` into one of the loops to see. Also, you can check out any error messages by adding `2>> error.txt` to the end of `host $name.$DOMAIN | grep "has address" | cut -d" " -f4` Error messages will display in error.txt – Jason Aug 03 '18 at 17:20
  • 1
    @Jason, ...the lack of quotes when you add an item means you aren't guaranteed that only (and at most) one will be added per iteration. – Charles Duffy Aug 03 '18 at 17:20
  • @CharlesDuffy, That is true as well. I was referring to why he is looping the second loop 5 times. – Jason Aug 03 '18 at 17:23
  • Oh, I see, I think the .txt is making it looping 5 times. But why the size of the array is printed as "1,3,4,4,4"? I think it should be "1,2,3,4,4,...." – user1156544 Aug 03 '18 at 17:23
  • Think you could provide the contents of list.txt? – Jason Aug 03 '18 at 17:24
  • I found it. So silly. It is because there can be more than one addition to the array per loop. So it is logical. I just expected that the command after `IPS+=` was getting only ONE result, but it can return more than one comma separated. Thanks all – user1156544 Aug 03 '18 at 17:25
  • 1
    @Jason: No, that would concatenate a string, not add a new element to an array. – choroba Aug 03 '18 at 17:32
  • ...see my comment on the question showing where the quotes *should* go (`ips+=( "$addr" )`). – Charles Duffy Aug 03 '18 at 17:36
  • =D Yeah. I misunderstood your comment. So if he wanted to do that in one line (without the blank check) he would do `ips+=("$(...)")`? – Jason Aug 03 '18 at 17:36