1

I have a list of lines in a Bash script as follows

if [ ! -z "$clone01" ]; then git clone "$clone01"; fi
if [ ! -z "$clone02" ]; then git clone "$clone02"; fi
if [ ! -z "$clone03" ]; then git clone "$clone03"; fi
#      $clone01 .... through to ...  $clone60
if [ ! -z "$clone60" ]; then git clone "$clone60"; fi

the leading zero at the end of the variable, when the number is less than 10, is important.

I have tried various substitutions and loops etc. This code is very repetitive, and there are 60 lines of it.

How can I create this code dynamically and make it part of my executed script? What is the optimal approach to this problem?

  • 2
    Do you have sixty variables named clone01 to clone60? – ilkkachu Dec 8 '17 at 14:25
  • @ilkkachu yes I do. I have numbers 1 all the way through to 60 – Kes Dec 8 '17 at 14:27
  • 1
    @Kes That's exactly what we were afraid to hear. – dr01 Dec 8 '17 at 14:50
  • @dr01 Thanks. This is all part of automating IDE Arduino install. In the past I often found I had to customise my old install for a specific library arrangement. Then, after a few months, I would return to Arduino IDE and couldn't then remember why the install was broken for a different sketch/ library set-up. I will now store specific Arduino set-up's as a bash script. It's going to save an awful lot of bother and re-discovery. Then I will not need so many libraries. I think ilkkachu has suggested below how the loop will only suck up as many libraries as there are. Thanks for the comment – Kes Dec 8 '17 at 15:19
5

Ok, don't do that, it's ugly. Either put the URLs in an array and loop over it:

urls=( http://this.git http://that.git )
for url in "${urls[@]}" ; do
    git clone "$url"
done

or put them in a file, one per line, and loop reading the lines. Here, it might be useful to guard for empty lines, just like you did. We could also ignore lines starting with # as comments:

while read -r url ; do
    if [ -z "$url" ] || [ "${url:0:1}" = "#" ]; then continue; fi
    git clone "$url"
done < file.with.urls

If you want the line counter too, it's easy to add with arithmetic expansions.

  • Thanks @Ilkkachu this answer solves the problem, indeed it took my paradigm a step further, and I can use numbers, below, up until, or larger than 60. It also allows me to store the url's in a neat array, introduce # comments above each url and skip the blanks between entries. A very neat solution and the solution I used. – Kes Dec 8 '17 at 17:59
  • 1
    @Kes, good! (plus a filler) – ilkkachu Dec 8 '17 at 18:06
3

Don't use eval to do this. Much better tool is variable indirection:

for i in clone{01..60}; do 
   [[ ${!i} ]] && git clone "${!i}"
done

[[ $var ]] does the same as [ ! -z "$var" ]. Note that storing 60 values in 60 variables is not the best approach and you might want to use arrays to do this.

  • 2
    as mentionned in my deleted answer, I learn a new bash trick today. – Archemar Dec 8 '17 at 15:03
  • @Archemar don't forget that eval is common misspelling of evil and in most cases variable indirection or namerefs (with bash 4.3 or later) are better options ;) – PesaThe Dec 8 '17 at 15:06
  • @PesaThe this answer solves the problem. Thank you. Ilkkachu's answer below is the one I used it took my paradigm a step further. – Kes Dec 8 '17 at 17:56
  • 1
    @Kes ilkkachu's answer uses arrays and is therefore really the better approach you should use ;) I merely introduced a way to make your code work as it is, with 60 variables. – PesaThe Dec 8 '17 at 18:42
1

Have you tried wrapping your if in a for loop like this one?

for i in clone{01..60}; do echo $i; done

This results in the following output:

clone01
clone02
clone03
... clipped for length ...
clone60

So something like this seems like it will do the trick:

for i in clone{01..60}; do if [ ! -z $i ]; then git clone $i; fi; done

Helpful resources for this:

http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-7.html

http://tldp.org/LDP/abs/html/varsubn.html

  • 1
    this will evaluate to string clone01 not value of $clone01. – Archemar Dec 8 '17 at 14:27
  • Thanks @Kevin-Nelson. I made a small modification to your helpful code, just after git clone as follows and now it works. Here you code I have working for i in clone{01..60}; do if [ ! -z $i ]; then git clone "${!i}"; fi; done – Kes Dec 8 '17 at 18:03
  • @Kes even though it seems correct, you really need to use indirection even inside [ ], just like it is in my answer. Only [ ! -z $i ] will always be true. – PesaThe Dec 8 '17 at 18:44

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.