LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   BASH scripting Question - Select loop displaying output (https://www.linuxquestions.org/questions/programming-9/bash-scripting-question-select-loop-displaying-output-914151/)

StaffSergeant 11-17-2011 08:19 PM

BASH scripting Question - Select loop displaying output
 
...

devUnix 11-18-2011 12:31 AM

Store Output of a Command to an Array
 
Quote:

Originally Posted by StaffSergeant (Post 4527067)
Catch is I want to limit it to so only 23 files display at a time so no files scroll off.

Here is the solution:

Code:

#!/bin/bash
FILES=($(ls -1))
Total_Files=${#FILES[@]}
Index=0
Count=0
while [ $Index -lt $Total_Files ];do
        [ $Count -eq 20 ] && { read -p 'Press the Enter/Return Key to Continue...';Count=0; }
        echo $Index : ${FILES[$Index]}
        let 'Index++'
        let 'Count++'
done
exit 0

Remove "$Index : " from the line above not to print the line numbers along with the file names:

Code:

echo ${FILES[$Index]}
Some Notes:

Storing the output of "ls -1" (you can use any other command, say "ls -ltr") command to an array:

Code:

FILES=($(ls -1))
Prompting for an input:

Code:

read -p 'Press the Enter/Return Key to Continue...'
The value is stored to $REPLY and we are simply discarding it; and resetting $Count to 0 (zero). Those two statements are inside { } so that we execute them as a group.

Modify the above script to suit your other requirements.

Cheers!

StaffSergeant 11-18-2011 10:23 AM

That's a while loop still, I would like it to be a select loop

grail 11-18-2011 12:52 PM

Quote:

Since you can't use | more
Why not?

StaffSergeant 11-18-2011 12:57 PM

| more does not will not work inside a select loop.

StaffSergeant 11-18-2011 02:54 PM

The reason I want a select loop is because eventually I will be running another select loop with functions in that. So the first select loop above will choose a file from the list, then the second loop will execute a function within side of that such as delete.

millgates 11-18-2011 04:06 PM

Quote:

Originally Posted by StaffSergeant (Post 4527817)
The reason I want a select loop is because eventually I will be running another select loop with functions in that. So the first select loop above will choose a file from the list, then the second loop will execute a function within side of that such as delete.

And you cannot do that with if/while?

To make things more complicated, select will print the options in multiple columns at the slightest provocation:

Code:

$ select file in $(seq 1 20); do echo $file; done
1) 1    3) 3    5) 5    7) 7    9) 9  11) 11  13) 13  15) 15  17) 17  19) 19
2) 2    4) 4    6) 6    8) 8  10) 10  12) 12  14) 14  16) 16  18) 18  20) 20
#?

Have you considered dialog? Something like
Code:

dialog --fselect ./ $height $width # will make a nice dialog to select a file
dialog --menu "Select operation:" $height $width $menu_height \
1 "delete" \
2 "move" \
3 "do something else with the file"

I found a nice short tutorial here

StaffSergeant 11-18-2011 04:26 PM

That is what I am working towards something like this:

INPUT1 = $1
INPUT2 = $2
INPUT3 = $3
VAR1 = 0
LENGTH = 0
if [[ INPUT2 == ""]]
then
while [ VAR1 = 0 ];
do
while [ Array.Length > Length ]
do
select VAR1 in Array:Length:Length:+19 "sort name" "sort size" "sort age" "more"
do
case
quit)
exit;;
"sort name") ;;
"sort size") ;;
"sort age") ;;
more) ;;
*)
esac
done
length=legnth+19
done
done
select
do
#commands in a case delete, copy,etc
done

fi

StaffSergeant 11-18-2011 04:39 PM

So I want to use the select loops to be able to select an item off the list (a file) then run another select loop and select an item off that list such as delete etc.

StaffSergeant 11-18-2011 05:03 PM

http://imgly.net/di-PBW3.jpg

This is what I have so far.

millgates 11-18-2011 06:38 PM

I still don't follow. What is wrong with example given by devUnix? To improve on that, it could look like:
Code:

#!/bin/bash

FILES_PER_SCREEN=20

select_file() {

        # some useful variables
        FILES=($(ls -1)) # breaks if filenames contain spaces
        Total_Files=${#FILES[@]}
        CHOICE1=""

        while [ x"$CHOICE1" = x ]; do
                Index=0
                Count=0

                # print all the files line by line
                while [ $Index -lt $Total_Files ];do

                        # if the screen is full wait for the user to either select a file or continue
                                [ $Count -eq $FILES_PER_SCREEN ] && {
                                      read -p 'Press the Enter/Return Key to Continue...' CHOICE1;
                                      Count=0;

                                # check that the input is an integer
                                [ x"$(echo "$CHOICE1"|tr -d [0-9])" = "x" ] || CHOICE1=""

                                # if the user selected a file, exit loop
                                [ x"$CHOICE1" == "x" ] || break
                        }
                        echo $Index : ${FILES[$Index]}
                        let 'Index++'
                        let 'Count++'
                done
        done

        # store the filename in the variable passed as $1
        eval $1=${FILES[$CHOICE1]}
}

select_file FILENAME
echo "Your choice is: $FILENAME"

select OPERATION in delete move copy; do
        [ "$OPERATION" = "delete" ] && rm "$FILENAME"
        # add the code to be done here...
done
exit 0

There is still a lot to improve. The code devUnix wrote for reading the output of ls will not work as expected, if the filenames contain spaces.

StaffSergeant 11-18-2011 06:54 PM

I mean I understand that its easier don't get me wrong. I am just working on an objective where it has to be select loops. I can do it in while loops, it's I am not use to select loops.

We need to prompt the user for a file, then they need to select it, then prompt them for a command to use, and both those need to be select loops. We can nest then in other loops.

millgates 11-18-2011 08:46 PM

sigh. Ok, how about something like this then?
Code:

#!/bin/bash

# let's have an array
declare -a FILES

# this might be a bit strange way to load those names into an array, but it will probably
# deal with the spaces correctly. I don't know if there's a point to this -- it's like
# 4am and I haven't got a clue about what I'm doing
for file in *; do FILES+=("$file"); done

# some variables --------------------------------------

# Number of files to print at a time
FILES_PER_SCREEN=20

# Number of files to move up and down when user selects
# "previous" or "next"
STEP=20

# our current position in the list -- index of the
# first filename to display
POS=0

# Total number of files in current directory
FILE_NUMBER=${#FILES[@]}

# index of the last filename to display
ENDPOS=$FILES_PER_SCREEN
[[ ENDPOS -ge FILE_NUMBER ]] && (( ENDPOS=$FILE_NUMBER - 1 ))

# Now let's store the entire array of available files in a string
# If there are files behind $ENDPOS, include the 'next' option
OPTIONS=$(for i in $(seq $POS $ENDPOS); do echo "${FILES[$i]}"; done;
        (( ($ENDPOS + 1) < FILE_NUMBER )) && echo "next")

# To check if the user wants to quit the program
QUIT=FALSE

# to treat only newlines as field separators ( so the names
# containing spaces don't break up
IFS='
'

# Main loop ===========================================
# will run until user chooses to quit
while [ x"$QUIT" = xFALSE ]; do
        clear
        # The outer select loop -------------------------------
        select SELECTED in $OPTIONS; do

                # Move down in the list
                if [ x"$SELECTED" = xnext ]; then
                              (( POS = $POS + $STEP ))
                        (( ENDPOS = $FILES_PER_SCREEN + $POS ))
                        [[ ENDPOS -ge FILE_NUMBER ]] && (( ENDPOS=$FILE_NUMBER - 1 ))
                        OPTIONS=$([ "$POS" -gt 0 ] && echo "previous";  for i in $(seq $POS $ENDPOS); do
                                echo "${FILES[$i]}"; done;
                                (( ($ENDPOS + 1) < FILE_NUMBER )) && echo "next")
                        break
                # Move up in the list
                elif [ x"$SELECTED" = xprevious ]; then
                        if [ "$POS" -le "$STEP" ]; then POS=0;
                        else (( POS = $POS - $STEP )); fi
                        (( ENDPOS = $FILES_PER_SCREEN + $POS ))
                        [[ ENDPOS -ge FILE_NUMBER ]] && (( ENDPOS=$FILE_NUMBER - 1 ))
                        OPTIONS=$([ "$POS" -gt 0 ] && echo "previous";  for i in $(seq $POS $ENDPOS); do
                                echo "${FILES[$i]}"; done;
                                (( ($ENDPOS + 1) < FILE_NUMBER )) && echo "next")
                        break
                elif [ x"$SELECTED" = x ]; then
                        break;

                else
                        # inner select loop ......................................................
                        select OPERATION in delete move quit; do
                                if [ x"$OPERATION" = x ]; then continue
                                elif [ x"$OPERATION" = xdelete ]; then
                                        rm "$SELECTED"
                                elif [ x"$OPERATION" = xquit ]; then exit 0
                                else
                                        echo "$OPERATION" # code to be executed
                                fi
                        done
                        # end of inner select .....................................................
                fi

        done
        # end of outer select ----------------------------------------------

done
# end of main loop ===============================================

There still is the problem of select using multiple columns sometimes, so there's no easy way to know how many lines will it take. But it shouldn't be more than about 23 as long as there's no line wrapping.
Another problem would be if there happened to be files named "previous" or "next" in the current directory.
But I'll leave that to you to deal with as an exercise :P

StaffSergeant 11-19-2011 10:23 PM

I am currently on 2 day order with my Army Unit, havn't had to look at it, just printed it and going to look at it at chow.

Thanks for the help though!

devUnix 11-20-2011 11:57 PM

Quote:

Originally Posted by StaffSergeant (Post 4527612)
That's a while loop still, I would like it to be a select loop

Put embed that while loop in your select select statements.


All times are GMT -5. The time now is 02:46 PM.