I was wondering if you could help me with something.
I want to write a menu for one of the scripts I'm working on. Currently, my script is:
echo "########################################"
echo "# Script tasks #"
echo "# #"
echo "# 1 Show running processes #"
echo "# 2 Show logged in users #"
... (continued)
echo "########################################"
However, when I run this inside of my script, for some reason some of the # signs at the end of the line get either indented into the box, or pushed further out, resulting in the right side of the box looking very bad and not well thought-out. I would like the right side of the box to look even (i.e., actually like a box).
I'm using Bash on Ubuntu 14.04 LTS and gedit as my text editor.
This isn't your question, but the way to do menus in a shell script is with the select command
# an array with the menu choices
choices=(
"Show running processes"
"Show logged in users"
"..."
)
# define the prompt
PS3="What is your choice? "
# display and get user input
# select is an infinite loop: `break` when you've done something successfully
select choice in "${choices[#]}"; do
case "$choice" in
"Show running processes")
some code here
break
;;
"Show logged in users")
some code here
break
;;
*)
echo "Please select a number from the menu."
# do not break, select will re-display
;;
esac
done
# if you need the choice afterward, you still have it
echo "$choice"
Related
I should put ENTER key value as a shell input to avoid shell waiting for user input.
echo 'enter'
read FRUIT
case "$FRUIT" in
"apple") echo "Apple pie is quite tasty."
;;
"banana") echo "I like banana nut bread."
;;
"kiwi") echo "New Zealand is famous for kiwi."
;;
esac
export TEST6=TEST
I have learned that 'echo' implicitly has an ENTER value, so tried to run below command to accomplish my requirement.
echo | source ~/.bash_profile
As I expected, I can see the OS prompt instead of seeing Shell wait the user input.
However, I noticed that the last line exporting TEST6 variable doesn't get exported. I mean I can't find the value of the variable TEST6.
Can you let me know what I am missing?
The value is being exported in a subshell run by the pipeline. Use input redirection instead.
source ~/.bash_profile <<< ""
Any string could be used, since you don't appear to care about the actual value used, but an empty string is the equivalent of what echo with no arguments produces. (All here strings implicitly end with a newline.)
If your shell does not support <<<, you can use a POSIX-standard here document instead.
. ~/some_file <<EOF
EOF
I have no problem creating the menu - that is not what this question is about.
What happens however is I go from having the arrow keys be useful (scroll up and down to get access to previous commands I've run at the command line) to completely useless (^[[A^[[A^[[A^[[B^[[C^[[D^[[C)
Is there any way to encapsulate that behaviour into a menu?
E.g. can I use the scroll up and down keys to access previous options I've selected. (It's a BIG menu and I have MANY options like dev.client.alpha or dev.otherclient.beta etc...)
I supposed I could break each one into separate files and just use the command line diredtly OR I could pass an augment to the menu so as to call: ~/menu dev.clint.alpha directly from the command line.
Just curious is anyone else has (had) this itch and if anything has ever been done about it?
Menu I'm presently using is done basically as follows:
while :
clear
do
echo "$MENU"
read CHOICE ARG1 ARG2 ARG3 ARG4 overflow
case $CHOICE in
command.a)
# do stuff here
;;
command.b)
# do different stuff here
;;
*) # catch all...
continue
;;
esac
done
clear
You can do what you want by enabling readline on your read,
and appending each choice reply to the internal history. You can even save
the history to a file so when you rerun the script you have the old
history. For example:
HISTFILE=/tmp/myhistory
history -r # read old history
while :
do echo "MENU. a b q"
read -e # sets REPLY, enables readline
history -s "$REPLY" # add to history
history -w # save to file
set -- $REPLY
CHOICE=$1; shift
ARG1=$1 ARG2=$2 ARG3=$3 ARG4=$4; shift 4
overflow="$*"
case $CHOICE in
a) echo do stuff here $ARG1 ;;
b) echo do different stuff here ;;
q) exit ;;
*) echo catch all...
continue ;;
esac
done
Okay, I have big list of servers and I wrote a bash script to enlist them. But the problem is that it scroll through the terminal.
I need a pagination view of those.
Is it possible to put more or less inside bash script?
say ,
1
.
.
.
1000
One page at a time.
I have this code:
Staging_Servers)
echo " Staging server list should go here"
;;
UAT_Servers)
echo " UAT server list should go here"
;;
Prod_Servers)
echo " Prod server list should go here"
;;
And one of them have long listing.
Once I run the script it shows menu like below:
1) Jenkin_Servers 5) Prod_Servers 9) DB-Staging
2) Nagios_Servers 6) Proxy_Servers 10) DB-Prod
3) Staging_Servers 7) Dedicated_Servers
4) UAT_Servers 8) Shared_Servers
Please enter the required number :
Okay once I give the number to the prompt one of the menu has lot of items which scroll of the screen. I want to see it by one page at a time.
Yes, you can invoke more or less in a bash script:
#!/bin/bash
...
cat file* | less
...
will start paginating output once it reaches the cat (or whatever command it is).
I used to write README files that had a first line consisting of:
#!/usr/bin/less
When you executed the README, it would paginate the README. Self paginating text files.
Store your server list in a string or array, and echo the output through your PAGER, or explicitly through less. For example:
export PAGER='/usr/bin/less'
case $list_name in
Staging_Servers)
echo "${staging_servers[#]}" | "$PAGER"
;;
UAT_Servers)
echo "${uat_servers[#]}" | "$PAGER"
;;
Prod_Servers)
echo "${prod_servers[#]}" | "$PAGER"
;;
esac
Well I've written a bat file which is used to load my pokemon backups for when I'm away from my gameboys, however I've converted to linux and I'm having issues getting the .BAT file in my exe (I've decompiled the exe back the the source) to work as a .SH and I can't really find much on how to use shell commands as the same function they would be in a BAT file :/ I would also love to know how to set the SH file to load out of the current directory AND run said program in wine.
Here is my .BAT file which works 100% perfectly under windows but refuses to run under wine or a CMD prompt portable under wine
`:MENU
CLS
ECHO ============= RawX GBA's =============
ECHO -------------------------------------
ECHO 1. Pokemon Crystal
ECHO 2. Pokemon Green
ECHO 3. Pokemon Gold
ECHO 4. Pokemon Pikachu
ECHO 5. Pokemon Ruby
ECHO 6. Pokemon Chaos Black
Echo 7. Pokemon Silver
ECHO 8. Pokemon White (NDS)
ECHO 9.
Echo 10.
Echo 11.
Echo 12. Pokemon Black (NDS)
ECHO ==========PRESS 'Q' TO QUIT==========
ECHO.
color fc
SET INPUT=
SET /P INPUT=Please select a number:
IF /I '%INPUT%'=='1' GOTO Selection1
IF /I '%INPUT%'=='2' GOTO Selection2
IF /I '%INPUT%'=='3' GOTO Selection3
IF /I '%INPUT%'=='4' GOTO Selection4
IF /I '%INPUT%'=='5' GOTO Selection5
IF /I '%INPUT%'=='6' GOTO Selection6
IF /I '%INPUT%'=='7' GOTO Selection7
IF /I '%INPUT%'=='8' GOTO Selection8
IF /I '%INPUT%'=='9' GOTO Selection9
IF /I '%INPUT%'=='10' GOTO Selection10
IF /I '%INPUT%'=='11' GOTO Selection11
IF /I '%INPUT%'=='12' GOTO Selection12
IF /I '%INPUT%'=='Q' GOTO Quit
CLS
ECHO ============INVALID INPUT============
ECHO -------------------------------------
ECHO Please select a number from the Main
echo Menu [1-9] or select 'Q' to quit.
ECHO -------------------------------------
ECHO ======PRESS ANY KEY TO CONTINUE======
PAUSE > NUL
GOTO MENU
:Selection1
:1
".\VisualBoyAdvance.exe" ".\Pokemon Crystal.zip"
goto menu
:Selection2
:2
".\VisualBoyAdvance.exe" ".\Pokemon Green.zip"
goto menu
:Selection3
".\VisualBoyAdvance.exe" ".\Pokemon Gold.zip"
goto menu
:Selection4
".\VisualBoyAdvance.exe" ".\Poke'mon Pikachu.zip"
goto menu
:Selection5
".\VisualBoyAdvance.exe" ".\Pokemon Ruby.zip"
goto menu
:Selection6
".\VisualBoyAdvance.exe" ".\Pokemon - Chaos Black.zip"
goto menu
:Selection7
".\VisualBoyAdvance.exe" ".\Pokemon Silver.zip"
goto menu
:Selection8
".\desmume.exe" ".\PokeWhite.zip"
goto menu
:Selection12
".\desmume.exe" ".\PokeBlack.zip"
goto menu
:Quit
CLS
ECHO ==============THANK YOU===============
ECHO -------------------------------------
ECHO ======PRESS ANY KEY TO CONTINUE======
PAUSE>NUL
EXIT`
The conversion to Bourne shell is pretty straightforward:
Add #!/bin/sh or similar as the first line, to tell Linux which interpreter to use. Unlike on Windows, there's more than one command shell, and more script interpreters than just shells besides.
The equivalent of the cmd.exe command CLS is clear on Linux.
Linux is case-sensitive, so all your ECHOs have to be lowercase. If I'd kept your IF statements in the translated version, they'd have to be lowercase, too.
echo in shell scripts doesn't just print everything literally to the end of the line, as in cmd.exe. Bourne shell is a much richer language: it can apply meaning to what appears after a command before sending it to the command. In your code, the single quotes (') and multiple spaces won't survive this command processing.
To avoid problems of this sort, I've double-quoted all of your echo strings. I could have done it selectively, double-quoting only the problem strings, but chose to double-quote everything for consistency. I don't want you to get the mistaken idea that echo in Bourne shell requires the double-quotes.
If I wasn't interested in keeping the translation simple, so you can see more 1:1 correspondences between batch files and shell scripts, I'd replace the two big blocks of echo commands with a heredoc.
echo. is just echo in Bourne shell. You don't need the dot in Bourne shell because echo in Bourne shell isn't overloaded to turn command echoing on and off, as with ECHO ON/OFF in cmd.exe. (Bourne shell does have a similar feature, enabled via set -x.)
It is possible to get colored output in Bourne shell, but there is no simple built-in command for it as in cmd.exe. If you want pretty colored menus, you can replace much of the code in this script with a call to dialog(1).
You use read to get input in a shell script; set does other things.
There is no goto in Bourne shell. We don't need it, because Bourne shell has decent control structures. I think a case statement expresses the intent of your inner selection code, and an infinite while loop expresses the outer "keep doing this until they hit q" scheme.
I don't see how code flow gets to your "press any key to continue" bit at the end, so I removed it. If I'm wrong, the rough equivalent of PAUSE is read -n 1 -s.
I have changed the calls to the external programs, dropping the .exe and changing .\ to ./ to match the way things are done on Linux. You still need to come up with Linux equivalents of VisualBoyAdvance.exe and desmume.exe.
The result looks something like this:
#!/bin/sh
clear
while true do
echo "============= RawX GBA's ============="
echo "-------------------------------------"
echo "1. Pokemon Crystal"
echo "2. Pokemon Green"
echo "3. Pokemon Gold"
echo "4. Pokemon Pikachu"
echo "5. Pokemon Ruby"
echo "6. Pokemon Chaos Black"
echo "7. Pokemon Silver"
echo "8. Pokemon White (NDS)"
echo "9."
echo "10."
echo "11."
echo "12. Pokemon Black (NDS)"
echo "==========PRESS 'Q' TO QUIT=========="
echo
echo -n "Please select a number: "
read input
case $input in
1)
./VisualBoyAdvance "Pokemon Crystal.zip"
;;
2)
./VisualBoyAdvance "Pokemon Green.zip"
;;
# etc.
q)
clear
exit
*)
clear
echo "============INVALID INPUT============"
echo "-------------------------------------"
echo "Please select a number from the Main"
echo "Menu [1-12] or select 'Q' to quit."
echo "-------------------------------------"
echo "======PRESS ANY KEY TO CONTINUE======"
esac
done
I have a very small script that needs to be run on debian installer: (via preseeding, pre installation script)
echo -n -e " # Your option [1] [2] [3]: "
read REPLY
if [ "$REPLY" == "1" ]
The script stops here and whatever I press is just displayed onto screen however it is not accepting the enter key. Normally, when you press 1 and press enter, the read should return 1 to $REPLY. But nothing happens. It keeps accepting user input but no further action happens.
Then, I switched to tty2 with ALT+F2 and run the script there, it was fine, it works as expected, when I press; it takes the input. Why tty1 is not accepting enter as usual?
Use debconf for that kind of configuration, it tackles exactly needs like yours.
Adapted example from the manual
Template file (debian/templates):
Template: your_package/select_option
Type: select
Choices: 1, 2, 3
Description: Which option?
Choose one of the options
Script (debian/config):
#!/bin/sh -e
# Source debconf library.
. /usr/share/debconf/confmodule
db_input medium your_package/select_option || true
db_go
# Check their answer.
db_get your_package/select_option
if [ "$RET" = "1" ]; then
# Do stuff
fi
Had the same problem (read not processing my input) with busybox on an embedded Linux.
Took me some time to realize that busybox's read is not CR-tolerant — my terminal program (used miniterm.py) sent CR/LF line ends by default; switching it to LF only solved my problem!
with bash interpreter, try replace read by :
builtin read
with other sh interpreter, specify the variable name :
read REPLY
The following script works fine for me:
#!/bin/sh
echo -n -e " # Your option [1] [2] [3]: "
read
case $REPLY in
1 )
echo "one" ;;
2 )
echo "two" ;;
3 )
echo "three" ;;
*)
echo "invalid" ;;
esac
It prints out one nicely if I choose 1. Any reason why you'd like to stick to if...fi?