Reputation: 597
Don't know where to ask for help so trying here. I'm creating a bash menu script with some operations and reading lots of bash tutorials but think my brain is starting to melt with all different syntax and ways to do it, can't fully wrap my head around bash/sh. End script will run on OSX for an art team.
A script to upload/download files with rsync. The script that will grab latest 'config/menu' from remote server. That file menu.txt will create an menu that lists project and when selected you get the option to download / upload.
Where I'm stuck is how to handle arrays to menus. Tried 2d arrays with no luck so now it's split into 3 arrays to hold the values I need. However when trying to display the menus I can't get it to work correctly. Look at the bottom for how to test, what is shows and what it should show.
This function parse the menu.txt to build an array that is used when showing a menu,
Project Title5, source1dir, destination1dir
Project Title6, source2dir, destination2dir
Project Title7, source3dir, destination3dir
Instead of gettin selection 1 'Project Title5' a menu will display
1) Project
2) Title5Project
3) Title6Project
4) Title7Quit
Script:
function create_menus() {
#operations for project
MENU_OPERATIONS=(
"Get latest from remote"
"Show changes from remote"
"Send latest from me to remote"
"Show changes from me to remote"
"Return to main menu"
)
#projects to choose from, load from textfile
declare -a t; declare -a s; declare -a d;
while IFS= read -r line; do
IFS=',' read -ra obj <<< "$line"
#TODO 2d array nicer than 3 arrays!
eval "t+=\"${obj[0]}\""
eval "s+=\"${obj[1]}\""
eval "d+=\"${obj[2]}\""
done <$FILE_MENU
t+="Quit" #add quit
MENU_MAIN=($t)
PROJECT_SOURCE=($s)
PROJECT_TARGET=($d)
}
then to show the main menu main_menu "${MENU_MAIN[@]}"
function main_menu
{
#clear
#header
PS3="Select project: "
select option; do # in "$@" is the default
if [ "$REPLY" -eq "$#" ];
then
echo "Exiting..."
break;
elif [ 1 -le "$REPLY" ] && [ "$REPLY" -le $(($#-1)) ];
then
# $REPLY = index
# $option = text
echo "You selected $option which is option $REPLY"
SELETED_PROJECT_TITLE=${MENU_MAIN[$REPLY]}
SELETED_PROJECT_SOURCE=${PROJECT_SOURCE[$REPLY]}
SELETED_PROJECT_TARGET=${PROJECT_TARGET[$REPLY]}
echo "Sel title $SELETED_PROJECT_TITLE"
echo "Sel source $SELETED_PROJECT_SOURCE"
echo "Sel target $SELETED_PROJECT_TARGET"
project_menu "${MENU_OPERATIONS[@]}" "$SELETED_PROJECT_TITLE" "$SELETED_PROJECT_SOURCE" "$SELETED_PROJECT_TARGET"
break;
else
echo "Incorrect Input: Select a number 1-$#"
fi
done
}
Here's full code https://github.com/fbacker/BigFileProjectsSync/blob/master/app.sh
ADDED MORE DESCRIPTION
To test:
git clone https://github.com/fbacker/BigFileProjectsSync.git
cd BigFileProjectsSync/
./app.sh
What happens:
Shows a menu with options:
1) Project
2) Title5Project
3) Title6Project
4) Title7Quit
Should happen:
Shows a menu with options:
1) Project Title5
2) Project Title6
3) Project Title7
4) Quit
app.sh > function create_menus() > This should create a menu based on the menu.txt file.
menu.txt one line is a project: first value is project name, second value is source directory and third is target directory.
Upvotes: 1
Views: 761
Reputation: 438093
Here's a fixed version of your create_menus()
function, which should do the trick:
function create_menus() {
#operations for project
# MENU_OPERATIONS=( # ... OMITTED FOR BREVITY
#projects to choose from
local -a titles sources destinations
local title source destination
while IFS='|' read -r title source destination; do
titles+=( "$title" )
sources+=( "$source" )
destinations+=( "$destination" )
done < <(sed 's/, /|/g' "$FILE_MENU")
# Copy to global arrays
MENU_MAIN+=( "${titles[@]}" )
PROJECT_SOURCE+=( "${sources[@]}" )
PROJECT_TARGET+=( "${destinations[@]}" )
MENU_MAIN+=( "Quit" ) #add quit
}
There were 2 crucial problems with your approach (I'll assume an array variable $arr
below):
In order to append a new element to an array, the new element must itself be specified as an array too; i.e., it must be enclosed in (...)
:
arr+=( "$newElement" )
- OK: value is appended as new element arr+=$newElement
- BROKEN: String-appends the value of $newElement
to $arr
's first element(!), without adding a new one.
arr=( 1 2 ); arr+=3; declare -p arr
-> declare -a arr='([0]="13" [1]="2")'
You can't copy a whole array with arrCopy=( $arr )
- all that does is to create a single-item array containing only $arr
's first element. To refer to an array as a whole, you must use "${arr[@]}"
(enclosing in "..."
ensures that no word-splitting is applied):
arrCopy=( "${arr[@]}" )
- OKarrCopy=( $arr )
- BROKEN - only copies 1st elementAlso note that it's better not to use all-uppercase shell-variable names in order to avoid conflicts with environment variables and special shell variables.
Upvotes: 1