0

I want to manipulate the expanded value of a variable that has been selected from an array after user input. Here's what I mean:

$ ./myscript.sh url2


#!/bin/bash

array=(Sigil wp2epub csskit)

Sigil       =   "https://github.com/Sigil-Ebook/Sigil.git"
csskit      =   "https://github.com/mattharrison/epub-css-starter-kit.git"
wp2epub     =   "https://github.com/mrallen1/wp2md.git"

if [ -z $1 ]; then
  echo "This script needs at least one parameter!"
  exit 1
fi

if [ $1 = Sigil ]; then
  ans=$Sigil # expanded
elif [ $1 = csskit ]; then
  ans=$csskit # expanded
elif [ $1 = wp2epub ]; then
  ans=$wp2epub # expanded
else
  echo "Please inform one of \
        Sigil, csskit or wp2epub!"
fi

git clone $ans

Explanation:

The script checks user input ($1), compares it to the array of possible variables, if found it retrieves the expanded value of that variable as the answer and then uses the expanded value (not the variable name).

I have been trying this for days, but my limited bash scripting abilities have not been enough...

Thanks in advance.


Per @terdon request: I want the user to inform the name of the variable in the array, which will be human friendly.

The variables are actually the names of packages that need to be fetched from github (git clone) and then recompiled and reinstalled.

Actual usage would be:

$ ./update.sh Sigil # Sigil is one of the variables

  • Please edit your question and clarify what will be in the array and what in the individual $urlN variables. What are the "expanded values"? Do you want the user to enter www.example.com and your script to retrieve a value linked to that URL? Or do you want your user to enter a string and the script to retrieve the URL associated with that script? Are you thinking of having your user enter the string url1 and have that expanded to $url1 in your script? – terdon Feb 9 '16 at 14:30
  • The lack of indentation in your code makes this unreadable. Also, are the other ifs meant to be elifs? – cat Feb 9 '16 at 14:38
  • @cat I rolled back your edit since your indentation didn't make much sense. The OP has essentially posted pseudocode (there's no fi, the various if should probably be elif etc) and your indentation made even less sense since it looked like there were nested contradictory if clauses. – terdon Feb 9 '16 at 15:30
  • @terdon It seemed less confusing this way, becuase right now it's just a bunch of syntax errors (missing two fis) but fair enough – cat Feb 9 '16 at 15:32
  • Why have you not chosen a favorite answer? It is polite to do so. – user79743 Feb 12 '16 at 0:30
0

In the script you present: $1 contains the name of an option, and an $array contains the value of the options. To get the result in the variable $ans expanded as you request, there are a couple of options:

Eval

An eval: expand $1 to Sigil for example, and assign $Sigil to ans:

eval ans\=\"\$\{"$1"\}\"

However, that assumes that $1 is a one word label of a variable. If the input has some other content, it may be possible that gets evaluated by eval. A more robust eval solution is to use ${array[i]} instead, as the contents of the array are controlled by the script.

Indirection

A close idiom in bash is ${!1}. That is get the value of var pointed by $1, exactly what we need. Again, more robustly with ${array[i]} (once the matching $array[i] is found:

a="array[i]"; ans="${!a}"

Associative Array

But all the problem of eval and indirection could be avoided if we use an associative array for both the array keys and the array values.

Then it is easy to find the correct value, if the array has a value, it is a valid value. If the array does not have a value for a key, the key is invalid.

A full script based on this concept may be as this:

#!/bin/bash

[ $# -lt 1 ] && {  echo "This script needs at least one parameter!"; exit 1; }

declare -A a
    a=(
    [Sigil]="https://github.com/Sigil-Ebook/Sigil.git"
    [wp2epub]="https://github.com/mattharrison/epub-css-starter-kit.git"
    [csskit]="https://github.com/mrallen1/wp2md.git"
    )


### Process an error while informing of options.
for    val in "${!a[@]}"
do     d=$d${d:+", "}$last
       last=$val
done
d="Please inform one of $d or $last"
SayError(){ echo "$d" >&2; exit 1; }



### Process a valid command execution.
ExecCmd(){ git clone "$ans"; }



### Process all arguments of script.
for    arg
do     unset ans                          ### unset result variable.
       printf -v ans '%s' "${a[$arg]}"    ### Assign result to "$ans"
       ${ans:+:} SayError                 ### If "$ans" is empty, process error.
       ${ans:+false} || ExecCmd           ### With valid "$ans" execute command.
done

The function SayError may be changed to eliminate the exit 1, the script will still process all arguments, with a warning for invalid values.

| improve this answer | |
2

Use an associative array:

#!/bin/bash

declare -A url
url=( [url1]="http://www.google.com"
      [url2]="http://www.yahoo.com"
      [url3]="http://www.bing.com"
    )

if [[ -z $1 ]] ; then
    echo "This script needs at least one parameter!"
    exit 1
elif [[ -z ${url[$1]} ]] ; then
    echo 'Unknown option'
    exit 1
fi

echo "Let's search ${url[$1]}."
| improve this answer | |
  • Upvoted for reducing it to simplest use case. Very helpful, I learned something about associative arrays from this. And I never realized you could split an array assignment across multiple lines. – Wildcard Feb 10 '16 at 3:51
0
arr=($url1 $url2 $url3)

for i in ${arr[@]}; do
  if [[ $i == $1 ]] ;then
    ans=$i
    break
  fi
done
| improve this answer | |

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.