BASH scripts : whiptail file select - bash

I've found a great little program that will allow me to add user friendly GUI's to my Bash Scripts;
whiptail
However the whiptail man page isn't all that helpful and doesn't provide any examples. After doing some google searches I understand how to create a simple yes/no menu using whiptail:
#! /bin/bash
# http://archives.seul.org/seul/project/Feb-1998/msg00069.html
if (whiptail --title "PPP Configuration" --backtitle "Welcome to SEUL" --yesno "
Do you want to configure your PPP connection?" 10 40 )
then
echo -e "\nWell, you better get busy!\n"
elif (whiptail --title "PPP Configuration" --backtitle "Welcome to
SEUL" --yesno " Are you sure?" 7 40)
then
echo -e "\nGood, because I can't do that yet!\n"
else
echo -e "\nToo bad, I can't do that yet\n"
fi
But what I would really like to build a file select menu using whiptail to replace some old code I have in a few different backup/restore bash scripts I have:
#!/bin/bash
#This script allows you to select a file ending in the .tgz extension (in the current directory)
echo "Please Select the RESTORE FILE you would like to restore: "
select RESTOREFILE in *.tgz; do
break #Nothing
done
echo "The Restore File you selected was: ${RESTOREFILE}"
I assume this has to be done via the '--menu' option of whiptail, but I am not sure how to go about it?
Any pointers?
Or can you point me in the direction of some whiptail examples?

Build an array of file names and menu select tags:
i=0
s=65 # decimal ASCII "A"
for f in *.tgz
do
# convert to octal then ASCII character for selection tag
files[i]=$(echo -en "\0$(( $s / 64 * 100 + $s % 64 / 8 * 10 + $s % 8 ))")
files[i+1]="$f" # save file name
((i+=2))
((s++))
done
A method like this will work even if there are filenames with spaces. If the number of files is large, you may have to devise another tag strategy.
Using alpha characters for the tags lets you press a letter to jump to the item. Numeric tags don't seem to do that. If you don't need that behavior, then you can eliminate some complexity.
Display the menu:
whiptail --backtitle "Welcome to SEUL" --title "Restore Files" \
--menu "Please select the file to restore" 14 40 6 "${files[#]}"
If the exit code is 255, the dialog was canceled.
if [[ $? == 255 ]]
then
do cancel stuff
fi
To catch the selection in a variable, use this structure (substitute your whiptail command for "whiptail-command"):
result=$(whiptail-command 2>&1 >/dev/tty)
Or
result=$(whiptail-command 3>&2 2>&1 1>&3-)
The variable $result will contain a letter of the alphabet that corresponds to a file in the array. Unfortunately, Bash prior to version 4 doesn't support associative arrays. You can calculate the index into the array of the file from the letter like this (notice the "extra" single quote):
((index = 2 * ( $( printf "%d" "'$result" ) - 65 ) + 1 ))
Example:
Welcome to SEUL
┌──────────┤ Restore Files ├───────────┐
│ Please select the file to restore │
│ │
│ A one.tgz ↑ │
│ B two.tgz ▮ │
│ C three.tgz ▒ │
│ D another.tgz ▒ │
│ E more.tgz ▒ │
│ F sp ac es.tgz ↓ │
│ │
│ │
│ <Ok> <Cancel> │
│ │
└──────────────────────────────────────┘

Whiptail is a lightweight reimplementation of the most popular features of dialog, using the Newt library. I did a quick check, and many features in Whiptail seem to behave like their counterparts in dialog. So, a dialog tutorial should get you started. You can find one here but Google is your friend of course. On the other hand, the extended example probably contains a lot of inspiration for your problem.

This function is part of my function repository for whiptail
# ----------------------------------------------------------------------
# File selection dialog
#
# Arguments
# 1 Dialog title
# 2 Source path to list files and directories
# 3 File mask (by default *)
# 4 "yes" to allow go back in the file system.
#
# Returns
# 0 if a file was selected and loads the FILE_SELECTED variable
# with the selected file.
# 1 if the user cancels.
# ----------------------------------------------------------------------
function dr_file_select
{
local TITLE=${1:-$MSG_INFO_TITLE}
local LOCAL_PATH=${2:-$(pwd)}
local FILE_MASK=${3:-"*"}
local ALLOW_BACK=${4:-no}
local FILES=()
[ "$ALLOW_BACK" != "no" ] && FILES+=(".." "..")
# First add folders
for DIR in $(find $LOCAL_PATH -maxdepth 1 -mindepth 1 -type d -printf "%f " 2> /dev/null)
do
FILES+=($DIR "folder")
done
# Then add the files
for FILE in $(find $LOCAL_PATH -maxdepth 1 -type f -name "$FILE_MASK" -printf "%f %s " 2> /dev/null)
do
FILES+=($FILE)
done
while true
do
FILE_SELECTED=$(whiptail --clear --backtitle "$BACK_TITLE" --title "$TITLE" --menu "$LOCAL_PATH" 38 80 30 ${FILES[#]} 3>&1 1>&2 2>&3)
if [ -z "$FILE_SELECTED" ]; then
return 1
else
if [ "$FILE_SELECTED" = ".." ] && [ "$ALLOW_BACK" != "no" ]; then
return 0
elif [ -d "$LOCAL_PATH/$FILE_SELECTED" ] ; then
if dr_file_select "$TITLE" "$LOCAL_PATH/$FILE_SELECTED" "$FILE_MASK" "yes" ; then
if [ "$FILE_SELECTED" != ".." ]; then
return 0
fi
else
return 1
fi
elif [ -f "$LOCAL_PATH/$FILE_SELECTED" ] ; then
FILE_SELECTED="$LOCAL_PATH/$FILE_SELECTED"
return 0
fi
fi
done
}
The use is simple
if dr_file_select "Please, select a file" /home/user ; then
echo "File Selected: \"$FILE_SELECTED\"."
else
echo "Cancelled!"
fi

I've tried following, which worked:
whiptail --title "PPP Config" --backtitle "Welcome to SEUL" --menu YourTitle 20 80 10 `for x in $(ls -1 *.tgz); do echo $x "-"; done`
you might change this into a multiple-liner as well, i've added checking for empty list:
MYLIST=`for x in $(ls -1 *.tgz); do echo $x "-"; done`
WC=`echo $MYLIST | wc -l`
if [[WC -ne 0]]; then
whiptail --title "PPP Config" --backtitle "Welcome to SEUL" --menu YourTitle 20 80 10 $MYLIST
fi
you need to adjust the numbers in order to get a cleaninterface. And you may replace the "-" by anything else if you want to. But if you don't, you will see 2 entries per line.
By the way: The selected entry is printed onto stderr.
This could need some more improving, but for a basic idea I think it's enough.

This seems to be one of the top results when you search for whiptail, and none of the previous results worked for me. This is what I wound up using:
#! /bin/bash
shopt -s nullglob
dir=`pwd`
cd /path/to/files
arr=(*.tgz)
for ((i=0; i<${#arr[#]}; i++)); do j=$((2*$i+2)); a[j]="${arr[$i]}"; a[j+1]=""; done
a[0]=""
# Next line has extra spaces at right to try to center it:
a[1]="Please make a selection from the files below "
result=$(whiptail --ok-button "OK button text" --cancel-button "Cancel Button Text" --title "Title Text" --backtitle "Text at upper left corner of page" --menu "Menu Text (not used??)" 30 160 24 "${a[#]}" 2>&1 >/dev/tty)
if [[ $? = 0 ]]
then
# ge 5 in next line should be length of file extension including . character, plus 1
[ ${#result} -ge 5 ] && outfile="/path/to/files/$result" || echo "Selection not made"
fi
cd "$dir"
$result will be empty if no valid selection was made. I added a dummy selection at the top of the list that returns an empty string as a result, so that you won't accidentally select the wrong file by accidentally hitting Enter right after the menu comes up. If you don't want that, then in the "for" line remove the +2 in "do j=$((2*$i+2))" and also the following two lines that set a[0] and a[1] explicitly.
The confusing thing about whiptail is that when reading from an array in a situation like this it expects two data items per line, both of which are displayed, the first being the result you want returned if the line is expected (which in some situations might be a letter or a number) and the second being whatever descriptive text you may want. That's why for the first line I use a[0] to give an empty string as the result, and a[1] as the descriptive text, but from there on the first item in the pair contains the filename (which is what I actually want returned) and the second is an empty string, since I don't want to display any text other than the filename on those lines.
Also a previous post said whiptail returned an error code of 255 if the cancel button was pressed, but that was not the case for the version I have - it returns 1. So I just test for an error code of 0 and if it is I assume it may be a valid entry, then I test for a valid string length (more than just the number of characters in the file extension, including the . character) to be sure.

Related

Bash error code doesn't show in my shell prompt [duplicate]

I've been trying to customize my Bash prompt so that it will look like
[feralin#localhost ~]$ _
with colors. I managed to get constant colors (the same colors every time I see the prompt), but I want the username ('feralin') to appear red, instead of green, if the last command had a nonzero exit status. I came up with:
\e[1;33m[$(if [[ $? == 0 ]]; then echo "\e[0;31m"; else echo "\e[0;32m"; fi)\u\e[m#\e[1;34m\h \e[0;35m\W\e[1;33m]$ \e[m
However, from my observations, the $(if ...; fi) seems to be evaluated once, when the .bashrc is run, and the result is substituted forever after. This makes the name always green, even if the last exit code is nonzero (as in, echo $?). Is this what is happening? Or is it simply something else wrong with my prompt? Long question short, how do I get my prompt to use the last exit code?
As you are starting to border on a complex PS1, you might consider using PROMPT_COMMAND. With this, you set it to a function, and it will be run after each command to generate the prompt.
You could try the following in your ~/.bashrc file:
PROMPT_COMMAND=__prompt_command # Function to generate PS1 after CMDs
__prompt_command() {
local EXIT="$?" # This needs to be first
PS1=""
local RCol='\[\e[0m\]'
local Red='\[\e[0;31m\]'
local Gre='\[\e[0;32m\]'
local BYel='\[\e[1;33m\]'
local BBlu='\[\e[1;34m\]'
local Pur='\[\e[0;35m\]'
if [ $EXIT != 0 ]; then
PS1+="${Red}\u${RCol}" # Add red if exit code non 0
else
PS1+="${Gre}\u${RCol}"
fi
PS1+="${RCol}#${BBlu}\h ${Pur}\W${BYel}$ ${RCol}"
}
This should do what it sounds like you want. Take a look a my bashrc's sub file if you want to see all the things I do with my __prompt_command function.
If you don't want to use the prompt command there are two things you need to take into account:
getting the value of $? before anything else. Otherwise it'll be overridden.
escaping all the $'s in the PS1 (so it's not evaluated when you assign it)
Working example using a variable
PS1="\$(VALU="\$?" ; echo \$VALU ; date ; if [ \$VALU == 0 ]; then echo zero; else echo nonzero; fi) "
Working example without a variable
Here the if needs to be the first thing, before any command that would override the $?.
PS1="\$(if [ \$? == 0 ]; then echo zero; else echo nonzero; fi) "
Notice how the \$() is escaped so it's not executed right away, but each time PS1 is used. Also all the uses of \$?.
Compact solution:
PS1='... $(code=${?##0};echo ${code:+[error: ${code}]})'
This approach does not require PROMPT_COMMAND (apparently this can be slower sometimes) and prints [error: <code>] if the exit code is non-zero, and nothing if it's zero:
... > false
... [error: 1]> true
... >
Change the [error: ${code}] part depending on your liking, with ${code} being the non-zero code to print.
Note the use of ' to ensure the inline $() shell gets executed when PS1 is evaluated later, not when the shell is started.
As bonus, you can make it colorful in red by adding \e[01;31m in front and \e[00m after to reset:
PS1='... \e[01;31m$(code=${?##0};echo ${code:+[error: ${code}]})\e[00m'
--
How it works:
it uses bash parameter substitution
first, the ${?##0} will read the exit code $? of the previous command
the ## will remove any 0 pattern from the beginning, effectively making a 0 result an empty var (thanks #blaskovicz for the trick)
we assign this to a temporary code variable as we need to do another substitution, and they can't be nested
the ${code:+REPLACEMENT} will print the REPLACEMENT part only if the variable code is set (non-empty)
this way we can add some text and brackets around it, and reference the variable again inline: [error: ${code}]
I wanted to keep default Debian colors, print the exact code, and only print it on failure:
# Show exit status on failure.
PROMPT_COMMAND=__prompt_command
__prompt_command() {
local curr_exit="$?"
local BRed='\[\e[0;91m\]'
local RCol='\[\e[0m\]'
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u#\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
if [ "$curr_exit" != 0 ]; then
PS1="[${BRed}$curr_exit${RCol}]$PS1"
fi
}
The following provides a leading green check mark when the exit code is zero and a red cross in all other cases. The remainder is a standard colorized prompt. The printf statements can be modified to present the two states that were originally requested.
PS1='$(if [ $? -eq 0 ]; then printf "\033[01;32m""\xE2\x9C\x93"; else printf "\033[01;31m""\xE2\x9C\x95"; fi) \[\e[00;32m\]\u#\h\[\e[00;30m\]:\[\e[01;33m\]\w\[\e[01;37m\]\$ '
Why didn't I think about that myself? I found this very interesting and added this feature to my 'info-bar' project. Eyes will turn red if the last command failed.
#!/bin/bash
eyes=(O o ∘ ◦ ⍤ ⍥) en=${#eyes[#]} mouth='_'
face () { # gen random face
[[ $error -gt 0 ]] && ecolor=$RED || ecolor=$YLW
if [[ $1 ]]; then printf "${eyes[$[RANDOM%en]]}$mouth${eyes[$[RANDOM%en]]}"
else printf "$ecolor${eyes[$[RANDOM%en]]}$YLW$mouth$ecolor${eyes[$[RANDOM%en]]}$DEF"
fi
}
info () { error=$?
[[ -d .git ]] && { # If in git project folder add git status to info bar output
git_clr=('GIT' $(git -c color.ui=always status -sb)) # Colored output 4 info
git_tst=('GIT' $(git status -sb)) # Simple output 4 test
}
printf -v line "%${COLUMNS}s" # Set border length
date=$(printf "%(%a %d %b %T)T") # Date & time 4 test
test=" O_o $PWD ${git_tst[*]} $date o_O " # Test string
step=$[$COLUMNS-${#test}]; [[ $step -lt 0 ]] && step=0 # Count spaces
line="$GRN${line// /-}$DEF\n" # Create lines
home="$BLD$BLU$PWD$DEF" # Home dir info
date="$DIM$date$DEF" # Colored date & time
#------+-----+-------+--------+-------------+-----+-------+--------+
# Line | O_o |homedir| Spaces | Git status | Date| o_O | Line |
#------+-----+-------+--------+-------------+-----+-------+--------+
printf "$line $(face) $home %${step}s ${git_clr[*]} $date $(face) \n$line" # Final info string
}
PS1='${debian_chroot:+($debian_chroot)}\n$(info)\n$ '
case "$TERM" in xterm*|rxvt*)
PS1="\[\e]0;${debian_chroot:+($debian_chroot)} $(face 1) \w\a\]$PS1";;
esac
Improved demure answer:
I think this is important because the exit status is not always 0 or 1.
if [ $EXIT != 0 ]; then
PS1+="${Red}${EXIT}:\u${RCol}" # Add red if exit code != 0
else
PS1+="${Gre}${EXIT}:\u${RCol}" # Also displays exit status
fi
To preserve the original prompt format (not just colors),
you could append following to the end of file ~/.bashrc:
PS1_ORIG=$PS1 # original primary prompt value
PROMPT_COMMAND=__update_prompt # Function to be re-evaluated after each command is executed
__update_prompt() {
local PREVIOUS_EXIT_CODE="$?"
if [ $PREVIOUS_EXIT_CODE != 0 ]; then
local RedCol='\[\e[0;31m\]'
local ResetCol='\[\e[0m\]'
local replacement="${RedCol}\u${ResetCol}"
# Replace username color
PS1=${PS1_ORIG//]\\u/]$replacement}
## Alternative: keep same colors, append exit code
#PS1="$PS1_ORIG[${RedCol}error=$PREVIOUS_EXIT_CODE${ResetCol}]$ "
else
PS1=$PS1_ORIG
fi
}
See also the comment about the alternative approach that preserves username color and just appends an error code in red to the end of the original prompt format.
You can achieve a similar result to include a colored (non-zero) exit code in a prompt, without using subshells in the prompt nor prompt_command.
You color the exit code portion of the prompt, while having it only appear when non-zero.
Core 2$ section of the prompt: \\[\\033[0;31;4m\\]\${?#0}\\[\\033[0;33m\\]\$ \\[\\033[0m\\]
Key elements:
return code, if not 0: \${?#0} (specificly "removes prefix of 0")
change color without adding to calculated prompt-width: \\[\\033[0;31m\\]
\\[ - begin block
\\033 - treat as 0-width, in readline calculations for cmdline editing
[0;31;4m - escape code, change color, red fg, underline
\\] - end block
Components:
\\[\\033[0;31;4m\\] - set color 0;31m fg red, underline
\${?#0} - display non-zero status (by removing 0 prefix)
\\[\\033[0;33m\\] - set color 0;33m fg yellow
\$ - $ or # on EUID
\\[\\033[0m\\] - reset color
The full PS1 I use (on one host):
declare -x PS1="\\[\\033[0;35m\\]\\h\\[\\033[1;37m\\] \\[\\033[0;37m\\]\\w \\[\\033[0;33m\\]\\[\\033[0;31;4m\\]\${?#0}\\[\\033[0;33m\\]\$ \\[\\033[0m\\]"
Note: this addresses a natural extension to this question, in a more enduring way then a comment.
Bash
function my_prompt {
local retval=$?
local field1='\u#\h'
local field2='\w'
local field3='$([ $SHLVL -gt 1 ] && echo \ shlvl:$SHLVL)$([ \j -gt 0 ] && echo \ jobs:\j)'"$([ ${retval} -ne 0 ] && echo \ exit:$retval)"
local field4='\$'
PS1=$'\n'"\e[0;35m${field1}\e[m \e[0;34m${field2}\e[m\e[0;31m${field3}\e[m"$'\n'"\[\e[0;36m\]${field4}\[\e[m\] "
}
PROMPT_COMMAND="my_prompt; ${PROMPT_COMMAND}"
Zsh
PROMPT=$'\n''%F{magenta}%n#%m%f %F{blue}%~%f%F{red}%(2L. shlvl:%L.)%(1j. jobs:%j.)%(?.. exit:%?)%f'$'\n''%F{cyan}%(!.#.$)%f '
Images of prompt

Reading in input from text file, Bash script

I am new to writing scripts in Bash and I am working on an assignment to make an inventory system. I have written all the scripts and they all work from using the standard input terminal. I now am looking to take the inputs from a text file called a1Input.txt which has all inputs on a new line.
r
9823
r
5430
c
7777
sml_widget
Small Widget (1 oz.)
6.99
15
50
Small, white, widget w/o packaging
r
7777
d
9823
r
9823
r
3293
u
3293
29.99
33
75
r
3293
The code for my initial bash script is this
#!/bin/bash
# assign1.bash
shopt -s nocasematch
option=""
until [ "$option" = "F" ]; do
echo "C - create a new item"
echo "R - read an existing item"
echo "U - update an existing item"
echo "D - delete an existing item"
echo "T - total price of an item"
echo "Choose a option"
read option
case $option in
C)
./create.bash
;;R)
./read.bash
;;U)
./update.bash
;;D)
./delete.bash
;;T)
./total.bash
;;*)
echo "Invalid input"
esac
done
What i would do to inject inputs from file to an interactive script is just:
cat a1Input.txt | ./interactive_script.sh
For example, imagine this simple script (copy-paste on terminal to create):
cat << EOF > questions.sh
#!/bin/bash
echo "What's your name ?"
read name
echo "What is your favourite movie ?"
read movie
echo "Hi \$name, i also love '\$movie' movie !!"
EOF
And these inputs:
cat << EOF > inputs.txt
Edu
Interstellar
EOF
Then, just execute:
chmod a+x questions.sh
cat inputs.txt | ./questions.sh
If your script is more complicated, consider using "expect", although this is quite complex.
BRs

Menu based shell script to delete files

My requirement is to delete file based on it displayed. Following is code snippet where I listed files but when I select option it displays file and when I capture file name its not happening only getting key not VALUE($REPLY only displays key but not value). Can someone help me out.
#!/bin/bash
select list in $(ls *.tmp)
do
echo $list
echo Do you want to delete files ?
read userInput
echo "UserInput is :: " $userInput
echo "Reply is :: " $REPLY
if [ $userInput == $REPLY ] ; then
# rm $REPLY
echo 'Yes'
break
done
----OUTPUT-----
1) +~JF1905393034413613060.tmp
2) +~JF2032005334435574091.tmp
3) +~JF3116454937363220082.tmp
4) +~JF3334986634800781310.tmp
5) +~JF3651229840772890748.tmp
6) +~JF3882306323060007639.tmp
7) +~JF573641658479505435.tmp
8) +~JF6137053351660236007.tmp
9) +~JF6277682393160684532.tmp
10) +~JF6385610668752278364.tmp
11) +~JF6824954027739238354.tmp
12) +~JF7876557427734797684.tmp
#? 4
+~JF3334986634800781310.tmp
Do you want to delete files ?
y
UserInput is :: y
Reply is :: 4
No
Try this:
PS3="Pick a file number to delete (or Ctrl-C to quit): "
select f in *.tmp ; do echo rm "$f" ; done
Then remove the echo to make it actually delete files.

bash-command to invert white-list of file paths to generate black-list

I want to convert a white-list of file paths into a black-list (minimum length) of file paths for a given directory.
I have a list of directories, that I want to keep with all subfolders and files in it.
I want to invert this information is the sense of getting: the minimum number of "delete directory with subfolders" commands so that the result is keeping the folders of the whitelist including subfolders and files. (Just to explain. I do not want to delete anything. )
Example:
data structure:
/A1/
A2/
B2/
A3
B3
C2/
/B1/
A2/
A3
B2
/C1/
A2
B2
/D1
whitelist.txt
/A1/B2 # also keep subdirs!
/C1/B2
wanted blacklist.txt
/A1/A2
/A1/C2
/B1 # no subdirs in whitelist -> no individual items here!
/C1/A2
/D1
I want to generate blacklist.txt
Is there a simple way to do it with bash commands?
Otherwise I would like to try it with python.
A bash script version
whitelist=( "./A1/B2" "./C1/B2" )
function run_path {
local cpath cdir wdir allb bdirs
cpath=${1:-.}
cpath=${cpath%/}
for wdir in "${whitelist[#]}"; do
if [[ $wdir = $cpath ]]; then
# break the recursive call
# exit_status <>0 => false
return 1
fi
done
allb=1
bdirs=()
for cdir in "$cpath"/*/; do
if [[ -d $cdir ]]; then
# exit_status <>0 => false : found whitelist item
if ! run_path "$cdir"; then
allb=0
else
bdirs+=("$cdir")
fi
fi
done
if [[ $allb = 0 ]]; then
for cdir in "${bdirs[#]}"; do
echo "$cdir"
done
return 1
fi
}
run_path "${cur_path}"

Checkboxes with bash script

I am trying to do a very simple bash script which emulates the behavior of checkboxes in appearance!
I want it to show some options and move the cursor to the next checkbox according to the key press of the left or right arrow keys. I've already managed to do this using READ and Ansii escape sequences to detect the arrow keys and I use tput to move the cursor.
My problem with this it's that I need to read a certain letter (x for instance) to be pressed and then take another action. But how can I detect this key press and at the same time detect if an arrow key it's being pressed or not?
To detect the ansii codes I need to read 3 characters and with the X character (the key to "select") I need to read just one, how can I read 3 characters and at the same time read just one?
Also I've been trying to make something so the user can JUST press the left or right arrow keys or the x key but if he presses ANY other key, nothing should happen!
I've done this this far:
#!/bin/bash
## Here I just print in the screen the "form" with the "checkboxes"
function screen_info(){
clear
cat <<EOF
/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_
||
|| 1[ ] 2[ ] 3[ ]
||
#############################
EOF
}
## This function detects the arrow keys and moves the cursor
function arrows(){
## I use ANSII escape sequences to detect the arrow keys
left_arrow=$'\x1b\x5b\x44' #leftuierda
right_arrow=$'\x1b\x5b\x43' #rightecha
just_x_key=""
## With tput I move the cursor accordingly
cursor_x=14
cursor_y=3
tput cup $cursor_y $cursor_x
while [ -z "$just_x_key" -o "$just_x_key" != "$just_x_key" ]; do
read -s -n3 key
while [ `expr length "$key"` -ne 3 ]; do
key=""
read -s -n3 key
break
done
case "$key" in
$left_arrow)
if [ $cursor_x -gt 14 ]; then
cursor_x=`expr $cursor_x - 8`
fi
tput cup $cursor_y $cursor_x
#This is supposed to be a simple condition detecting the x key pressed which I want to trigger something... But how to read a single character to this condition and 3 characters at the same time if the user presses the arrow key ???? =/
#read -s just_x_key
#if [ $just_x_key == x ]; then
# echo X
# tput cup 7 15
# echo "YOU PRESSED THE RIGHT KEY!!! =D"
#fi
;;
$right_arrow)
if [ $cursor_x -lt 28 ]; then
cursor_x=`expr $cursor_x + 8`
fi
tput cup $cursor_y $cursor_x
#read -s just_x_key
#if [ $just_x_key == x ]; then
# echo X
# tput cup 7 15
# echo "YOU PRESSED THE RIGHT KEY!!! =D"
#fi
;;
esac
done
exit $?
}
#EXECUTION
#=========
## I just call the functions!
screen_info
arrows
Yes I know, it's not the most perfect code ever but I'm trying to learn. Suggestions will be very appreciated.
If you just want the checkboxes in a script, you can use the whiptail(1) or dialog(1) tools to create the checkboxes:
$ whiptail --checklist "Please pick one" 10 60 5 one one off two two off\
three three off four four off five five off
┌──────────────────────────────────────────────────────────┐
│ [ ] one one │
│ [*] two two │
│ [ ] three three │
│ [*] four four │
│ [ ] five five │
│ │
│ <Ok> <Cancel> │
│ │
└──────────────────────────────────────────────────────────┘
"two" "four"$
The final "two" "four" is the selected entries returned from the whiptail(1) program.
If you're programming this for the fun of it yourself, let me know and I'll just convert this to a comment in the hopes that someone else will find the hint useful in the future.
Alternatively, you can use my library at
https://sites.google.com/site/easybashgui
It detects automatically if dialog or whiptail is installed.
(Normally, at least one of two is always present even in bare systems...)
So your scripts becomes:
source easybashgui; menu 1 2 3 ; clean_temp
Why reinventing the wheel?
;P

Resources