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

6
  • 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 stringurl1 and have that expanded to $url1 in your script?
    – terdon
    CommentedFeb 9, 2016 at 14:30
  • The lack of indentation in your code makes this unreadable. Also, are the other ifs meant to be elifs?
    – cat
    CommentedFeb 9, 2016 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
    CommentedFeb 9, 2016 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
    CommentedFeb 9, 2016 at 15:32
  • Why have you not chosen a favorite answer? It is polite to do so.
    – user79743
    CommentedFeb 12, 2016 at 0:30

3 Answers 3

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]}." 
1
  • 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
    CommentedFeb 10, 2016 at 3:51
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.

    0
    arr=($url1 $url2 $url3) for i in ${arr[@]}; do if [[ $i == $1 ]] ;then ans=$i break fi done 

      You must log in to answer this question.

      Start asking to get answers

      Find the answer to your question by asking.

      Ask question

      Explore related questions

      See similar questions with these tags.