LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   How to compare the user input in bash scripting? (https://www.linuxquestions.org/questions/programming-9/how-to-compare-the-user-input-in-bash-scripting-4175660158/)

bmxakias 09-01-2019 11:49 AM

How to compare the user input in bash scripting?
 
Hello

I have some folders like:


Code:

/backup/$DOMAIN/$DATE/database//inc/inc1
/backup/$DOMAIN/$DATE/database/inc/inc2
/backup/$DOMAIN/$DATE/database/inc/inc3

I am using this code:

Code:

    echo ""
    echo "Available increamental backups :"
    echo ""

PS3="

Please select the incremental backup point to restore [1, 2, 3 e.t.c]:"
# get the folders count
count=$(ls -1td $INCDIR/*/ | wc -l)

select domainbackupdate in $(ls -1td $INCDIR/*/ | awk -F/ '{print $(NF-1)}'); do
  # if input is a number and is less than or equal to count
  if (( $REPLY && $REPLY <= $count )) 2> /dev/null; then
    break
  else
    echo "Your input ${REPLY} is not available. Please select a number from the list:"
  fi
done

    echo "Please wait..." ;;

It does check in the folder $INCDIR/*/ all folders and shows them by order (newest first) like:

Code:

Available increamental backups :

1) inc3
2) inc2
3) inc1


Now what i would like to do is to get the input from the user selection (probably using the read command? ) and if the user select:

1 to run a command for folder inc1
2 to run a command for folder inc1 and then inc2
3 to run a command for inc1 and then inc2 and then inc3

But the problem is that what i will have in 1) or 2) or 3) may not be always the same...

So i must be able to read if it is just inc1 and run a simple cmmand or inc3 and run the 3 needed commands....

Is it possible to do that?

To work it must go from inc1 up to selected inc(x) that the user will select..

Thank you

Firerat 09-01-2019 11:58 AM

yeah, you need to use a bash builtin called select.

We did some crafty things with that the other day
I'll find the link and edit this post for you


Edit
https://www.linuxquestions.org/quest...ds-4175659851/

you should get what you need from that

post what you come up if you get stuck

michaelk 09-01-2019 12:09 PM

Use $domainbackupdate. Its value will be one of the items in the output of the ls command i.e. inc1,inc2 or inc3 in your posted example. So the solution is easier then you think.

There are lots of string manipulation tools to separate the number from inc and then you can use a loop to go from inc1 to the selected inc(x).

https://bash.cyberciti.biz/guide/Select_loop

rnturn 09-01-2019 12:29 PM

Quote:

Originally Posted by bmxakias (Post 6032022)
Code:

Please select the incremental backup point to restore [1, 2, 3 e.t.c]:"
# get the folders count
count=$(ls -1td $INCDIR/*/ | wc -l)

select domainbackupdate in $(ls -1td $INCDIR/*/ | awk -F/ '{print $(NF-1)}'); do
  # if input is a number and is less than or equal to count
  if (( $REPLY && $REPLY <= $count )) 2> /dev/null; then
    break
  else
    echo "Your input ${REPLY} is not available. Please select a number from the list:"
  fi
done


You can use "select" but I've always found that to be an ugly way to go if there are a lot of options. I normally like to make an interface like that screen oriented and read everything that would be a possible option into an array and calculate indices that provide a window into the array and then display only as many as the user's terminal size can hold reserving space for prompting and reading the user's input, and reminders about the "previous screen" and "next screen" options. Takes a bit more effort to code but I think it's more user friendly. Depends on your end-user's needs. When I last used the method above, I was working with SQL developers who a.) sometimes had directories that often had hundreds datasets that they needed to select from for testing and b.) an aversion to organizing their data into logical subdirectories with smaller numbers of files in each. They appreciated the screen-oriented approach rather than having to scroll through a long list of options.

I'll hunt for a simple example of this approach and post it if anyone's interested in seeing it. (Right now I'm off to the hardware store to polish of couple of tasks in the Job Jar. :^) )

bmxakias 09-01-2019 01:03 PM

I think that all solutions are related on how to get the user input and act on that....but on my case i need the script to understand the input number of the folder name like inc3 and then then to run a command for inc1 and then for inc2 and then for inc3 and then stop.

Maybe my knowledge is limited on that but i can't see on the provided links that functionality ... Maybe i didn't explain it well ? :(

Thanks for your replies !

bmxakias 09-01-2019 01:25 PM

To explain it a bit better...

If user select the folder inc1 that can have any number at the selection menu i would like to run this command:

Code:

touch /backup/$DOMAIN/$DATE/database/inc/inc1/file.txt
If user select for example the folder inc3 that can have any number at the selection menu i would like to run this:

Code:

touch /backup/$DOMAIN/$DATE/database/inc/inc1/file.txt
touch /backup/$DOMAIN/$DATE/database/inc/inc2/file.txt
touch /backup/$DOMAIN/$DATE/database/inc/inc3/file.txt

Thank you !

Firerat 09-01-2019 01:52 PM

in the link I posted we talked about how to decide what to do once the user had selected the option

so if user selects inc3
to recreate that you first restore inc1, then inc2 and finally inc3

if user selects inc2
to recreate that you first restore inc1 and finally inc2

if user selects inc1
restore inc1


ok

you built an array starting at 0
0=inc1
1=inc2
2=inc3

then with select presented it as

1) 2=inc3
2) 1=inc2
3) 0=inc1

Code:

Count of backups is 3

REPLY=1 ( 2=inc3 )
Count-REPLY = 2 .. 3 - 1 = 2
for 0 1 2;do
  restore incX
done


REPLY=2 ( 1=inc2 )
Count-REPLY = 1 .. 3 - 2 = 1
for 0 1;do
  restore incX
done

REPLY=3 ( 0-inc1 )
Count-REPLY = 0 .. 3 - 3 = 0
for 0;do
  restore inc
done

so, unchecked code

Code:

Dirs=## array comes from code I wrote in the other thread
# which needs check for gaps
# it is a lil dumb

for ((i=0;i<$(($Count - $REPLY));i++));do
    restore "${Dirs[i]}"
done


does that make sense?
Note : /!\ things like that are out by 1 if they are wrong ;)

Firerat 09-01-2019 03:08 PM

Code:

#!/bin/bash
Dir="$1"

[[ $Dir == test ]] \
    && mkdir -p testing/inc{1..3} \
    && Dir="testing/inc"
# Edit1: I had Dir being set to testing all the time
# Doh!
Dirs=()

for i in ${Dir}*;do
    [[ ${i} =~ ${Dir}[0-9]+ ]] && Dirs+=("${i}")
done

for (( i=$(( ${#Dirs[@]} - 1)) ; i >= 0; i-- ));do
    SelectDir+=("${Dirs[i]}")
done

select CHOICE in "${SelectDir[@]}";do
    [[ "$CHOICE" ]] && break
done

for ((i=0;i <= $((${#Dirs[@]} - $REPLY));i++));do
    echo restore "${Dirs[i]}"
done

but check what happens if you have more than 9 dirs!!

michaelk 09-01-2019 03:31 PM

If you choose inc3 the value of $domainbackupdate will equal inc3. Using a substring function you can assign a variable to equal 3 in this case.

From there you can create a loop from 1 to 3 to create the file.txt files in each incx directory without knowing the order of the select menu.

Firerat 09-01-2019 04:16 PM

yeah true


Code:

select CHOICE in "${Dirs[@]}";do
  [[ "$CHOICE" ]] && break
break
echo "$REPLY"
echo "$(( $REPLY - 1 ))"
echo "${Dirs[$(( $REPLY - 1 ))]}"
echo "${Dirs[$(( $REPLY - 1 ))]##*/}"
getnumber="${Dirs[$(( $REPLY - 1 ))]##*/}
getnumber="${getnumber//[^[:digit:]]/}"
echo $getnumber

if the array is in numerical order you just need to know which direction to walk

you can get the digit from the string and reconstruct, but you already have all that
bash will have globbed in numerical order

reconstructing negates the need for 000pad
but the order things are presented in will look messy
000pad and reconstruct needs more work to strip the leading 0s ( 08 != 8 )

gaps ( inc1 inc3 # inc2 is missing ) will break .. well both I guess
the reconstructed won't find inc2
with the array the restore will fail ( I assume inc3 depends on inc2)

This is where metadata needs to be put in the backups,
a first pass checks the dependencies and then restores once it confirms they are satisfied

which makes it even easier, since inc3 we check inc3/metadata and it says well I need inc2 first, inc2/metadata says well, I need inc1 first

so we only need to run restore on "${Dirs[$(( $REPLY - 1 ))]}"

does that make sense?

bmxakias 09-02-2019 04:44 AM

Thanks for your replies !!!!

The inc folders may be up to 46 ....

Can you please adjust your code for that so i can see the difference ?


Also if it is easier to do it by changing anything in the paths names, it's ok to do that...

For example if 1inc, 2inc or 1-inc, 2-inc is better for the script.....

Firerat 09-02-2019 05:29 AM

you need to pad the 1 2 3 with leading zeroes 001 002 003 .. 999 1000 /!\ 1000 breaks it

you could use printf to pad
revisit the creation part
https://www.linuxquestions.org/quest...me-4175660121/


This is inspired by GazL's post

I added option to order Ascending/Descending

Code:

#!/bin/bash
Dir="${1%/}"

[[ $Dir == test ]] \
    && mkdir -p testing/inc{1..3} \
    && Dir="testing/inc"

Dirs=() # initial array ${#Dirs[@]} == 0
for i in ${Dir}*;do
    [[ ${i} =~ ${Dir}[0-9]+ ]] && Dirs+=("${i}")
done

Ascending(){
    choose "${Dirs[@]}"
return $?
}
Descending(){
    choose $(
      for (( i=$(( ${#Dirs[@]} - 1 )) ; i >= 0; i-- ));do
          printf "%s " "${Dirs[i]}"
      done
      )
return $?
}
choose(){
    select CHOICE in "${@}";do
        [[ "$CHOICE" ]] && break
    done
    restore "${CHOICE}"
return $?
}
restore(){
# restore function
echo restoring "${1}/metadata"
}

select order in Ascending Descending;do
    [[ "$order" ]] && $order && break
done


bmxakias 09-02-2019 09:45 AM

Can you please remove from your code the creation of the folders (as i do that from the backup script) and i already adjust it and now i have:

Code:

/backup/$DOMAIN/$DATE/database//inc/inc001
/backup/$DOMAIN/$DATE/database/inc/inc002
/backup/$DOMAIN/$DATE/database/inc/inc003


Also Ascending/Descending doesn't matter .... we may remove that also....

I just need to list folders and get the user input ...

With the above code i am getting the Ascending/Descending menu but i don't see anything listed to select and see if it works...

Thank you

BW-userx 09-02-2019 09:50 AM

N/M

Firerat 09-02-2019 10:01 AM

:D

bless

I was just trying to inspire , not actually write it for you

look at them as working examples, not working scripts.


out of interest, how did you pad with 00?


All times are GMT -5. The time now is 08:11 PM.