LinuxQuestions.org
Go Job Hunting at the LQ Job Marketplace
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Distributions > Slackware
User Name
Password
Slackware This Forum is for the discussion of Slackware Linux.

Notices

Reply
 
Search this Thread
Old 10-29-2005, 03:58 AM   #1
Woodsman
Senior Member
 
Registered: Oct 2005
Distribution: Slackware 14.1
Posts: 3,482

Rep: Reputation: 534Reputation: 534Reputation: 534Reputation: 534Reputation: 534Reputation: 534
Question Bash scripting and user input


Looking for some nudging to help me write a bash script.

I'm browsing the bash tutorials, but am coming up short with additional examples that will help me. I want to do the following:

Code:
if [ ! -z $PS1 ] ; then
    # Is this script being run manually? Don't ask this question if non-interactive.
    echo "Warning message: blah, blah, blah."
    echo -n "Do you want to continue? (any response other than y/yes will terminate the script)."
    read response
    if [ $response != y ] && [ $response != Y ] && [ $response != yes ] && [ $response != YES ] ; then
       # would be nice if I could parse the first letter typed
       exit
    fi
fi
# continue script . . .

umount /mnt/*
# terminate script if umount fails to unmount any partition

# continue script . . .
How do I ignore case (similar to BASIC LCase command)?
How do I parse the response (similar to BASIC Left(String,1) command)?

Additionally, the script will unmount /mnt partitions using umount /mnt/*. I would like the script to terminate gracefully, with an error message to the screen, if the umount command fails while trying to unmount any partition.

I'm not asking for a full fledged script, just some help or nudging in the correct direction or some links that will help me learn. I am the only one running this script. Therefore I "know" what responses will work properly, but I'd like to use this exercise to improve my knowledge of bash and write a more [strikethrough]idiot-proof[/strikethrough] robust script.

TIA!

P.S. Is there no strikethrough bbcode at this board like at other boards?
 
Old 10-29-2005, 07:21 AM   #2
unSpawn
Moderator
 
Registered: May 2001
Posts: 27,469
Blog Entries: 54

Rep: Reputation: 2900Reputation: 2900Reputation: 2900Reputation: 2900Reputation: 2900Reputation: 2900Reputation: 2900Reputation: 2900Reputation: 2900Reputation: 2900Reputation: 2900
How do I ignore case
Say you want to match responses y, yes and yeah, you could grep case-insensitive:
echo "$response"|grep -qie "y[a-z]\{0,3\}" && do_cmd
or convert case:
case "$(echo "$response"|tr "[A-Z]" "[a-z]")" in y|yes|yeah) do_cmd;; *) exit 1;; esac


How do I parse the response
See "man test"?, BTW write this:
if [ $response != y ] && [ $response != Y ] && [ $response != yes ] && [ $response != YES ] ; then
as:
if [ $response != y -o $response != Y -o $response != yes -o $response != YES ] ; then
, but convert to lower + "case" should be easier here.


I would like the script to terminate gracefully, with an error message to the screen, if the umount command fails while trying to unmount any partition.
You're looking for the exit status of a command (echo "$?"), but using "umount /mnt/*" isn't gonna work right if you want to show the status for all devices, besides you don't want to exit if it fails on the first umount?

# Since everything is mounted through /proc we'll take input from there.
# This way we avoid globbing symlinks and don't umount stuff that isn't mounted.
grep "^/dev/[h,s]d" /proc/mounts | while read garbage part; do
echo -en "Umounting ${part}: "; umount "$part" 2>&1>/dev/null; case "$?" in 0) r=OK;; *) r=FAILED;; esac; echo $r
done

If you OTOH would only want to be shown errors on exit:
parts=""; grep "^/dev/[h,s]d" /proc/mounts | while read no part; do
umount "$part" 2>&1>/dev/null; case "$?" in 0) ;; *) parts="$parts $part";; esac
done; echo "These partitions failed to umount properly: ${parts}"


improve my knowledge of bash and write a more idiot-proof robust script.
That starts IMHO by not trusing sanitising user input.
Here's a stupid example that only allows some chars to be used:
# Read-only variable
declare -r allowedchars="/._-1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
expr index "$response" "${allowedchars}" >/dev/null || ( echo "Input contains illegal chars, exiting."; exit 1 )


P.S. Is there no strikethrough bbcode at this board like at other boards?
No. Use a felt tip pen :-]
 
Old 10-29-2005, 08:47 AM   #3
Alien Bob
Slackware Contributor
 
Registered: Sep 2005
Location: Eindhoven, The Netherlands
Distribution: Slackware
Posts: 5,308

Rep: Reputation: Disabled
Re: Bash scripting and user input

Quote:
Originally posted by Woodsman
How do I parse the response (similar to BASIC Left(String,1) command)?
Use ${response:0:1} if you're interested in only the 1st character of the response.
Like this:
Code:
if [ ${response:0:1} != y -o ${response:0:1} != Y ]; then ........
Eric
 
Old 10-29-2005, 09:39 AM   #4
Rojon
Member
 
Registered: Aug 2005
Location: UK
Distribution: Slackware
Posts: 41

Rep: Reputation: 15
Not sure if this will help or not but the last time i wanted to do something depending on user input i used the case statement (i suppose it is similar to a previous example).

Code:
read ANSWER
        # determine user input
        case "$ANSWER" in
	       "Y"|"y")
		      Do something...
	              echo "Done something!"
	              ;;
	       "N"|"n")
		     echo "Exiting!"
	             exit 0
                     ;;
       esac
Hope that helps..

Cheers
 
Old 10-30-2005, 06:57 PM   #5
Woodsman
Senior Member
 
Registered: Oct 2005
Distribution: Slackware 14.1
Posts: 3,482

Original Poster
Rep: Reputation: 534Reputation: 534Reputation: 534Reputation: 534Reputation: 534Reputation: 534
Wow. Way too much for my puny brain. Actually, there is some good info here that I want to sift and use.

For example, I like the idea of limiting user input. From the above example, if I want to limit input to n/N/y/Y do I merely delete all of the characters except those four? That is, would I type:

allowedchars="nyNY"

Additionally, if one of those four characters is not entered, how do I loop back to my originating question, rather than exiting the script? Yeah, I know, I did not ask or infer that in my original post.

Parsing the first character of the response: ${response:0:1}. That looks slick. With that tip I eventually found the convention mentioned in the Advanced Bash Scripting guide. Cool!

My original question is backup related. Thus, I want to still test if my umount command works (using /proc/mount as described above), but I also want to still query the user (me) if I am sure I want to continue. Grep is still A Strange Thing to me, but I'll use the examples provided to hopefully go further.

Regarding the ability to return the exit status of a command, the above example used echo "$?" as part of a case-esac procedure. After some quick surfing I think I can conclude that this command is a special 'nix variable? I'm trying to learn more about this because I have another script where I need to know this information.

Question: I notice that many people often end their scripts with exit 0. Is this A Good Thing or common practice? I notice PV does this in most or all of his rc.d scripts. What is the reasoning behind this practice?
 
Old 10-31-2005, 03:54 AM   #6
Alien Bob
Slackware Contributor
 
Registered: Sep 2005
Location: Eindhoven, The Netherlands
Distribution: Slackware
Posts: 5,308

Rep: Reputation: Disabled
You could try this:

Code:
allowedchars="YyNn"
response=
while ! [[ "${response:0:1}" =~ "[$allowedchars]" ]] ; do
  read -er -p "Do you want to continue? (y/n): " response
done
This code block will keep asking the same question until the answer starts with either N,n,Y or y.
Then you can evaluate the response and act upon it.

Eric
 
Old 10-31-2005, 12:16 PM   #7
Rojon
Member
 
Registered: Aug 2005
Location: UK
Distribution: Slackware
Posts: 41

Rep: Reputation: 15
Quote:
Question: I notice that many people often end their scripts with exit 0. Is this A Good Thing or common practice? I notice PV does this in most or all of his rc.d scripts. What is the reasoning behind this practice?
exit ends the shell script with a status code.

- zero equals success
- nonzero equals failure

Hope that helps.
 
Old 10-31-2005, 07:12 PM   #8
Woodsman
Senior Member
 
Registered: Oct 2005
Distribution: Slackware 14.1
Posts: 3,482

Original Poster
Rep: Reputation: 534Reputation: 534Reputation: 534Reputation: 534Reputation: 534Reputation: 534
Quote:
This code block will keep asking the same question until the answer starts with either N,n,Y or y.
Then you can evaluate the response and act upon it.
Thanks Eric! This will help.

Quote:
exit ends the shell script with a status code.

- zero equals success
- nonzero equals failure
I understand that part, but I was seeking a response geared more about the overall philosophy of ending a script with exit 0. Why bother? That is, I presume after ample testing of a script everything works as expected and if one embeds reasonable error trapping within the script, then the script always terminates gracefully. So why include exit 0 as the last line in a script?
 
Old 11-01-2005, 03:00 AM   #9
Alien Bob
Slackware Contributor
 
Registered: Sep 2005
Location: Eindhoven, The Netherlands
Distribution: Slackware
Posts: 5,308

Rep: Reputation: Disabled
Quote:
Originally posted by Woodsman
I understand that part, but I was seeking a response geared more about the overall philosophy of ending a script with exit 0. Why bother? That is, I presume after ample testing of a script everything works as expected and if one embeds reasonable error trapping within the script, then the script always terminates gracefully. So why include exit 0 as the last line in a script?
It can even have unexpected results to end a script with the exit statement.
Several scripts are being "sourced" in Slackware's init scripts (i.e. run like ". somescript" which can also be written as "source somescript"). The "." or "source" command is a shell internal command. Sourcing a script means that the script is executed in the current shell instead of spawning another shell to run the script's commands.
Now, if the sourced script calls "exit", your parent script will exit too, right there!

Try this:

Copy this into a shell script, call it test1.sh and make it executable:
Code:
#!/bin/sh
echo "About to take test2"
. test2.sh
echo "I passed test2"
Copy this into a second shell script, call this one test2.sh and make it executable:
Code:
#!/bin/sh
echo "I am inside test2 now"
exit 0
And then test these by running

Code:
./test1.sh
Now, change the line ". test2.sh" in the test1.sh script so that it reads "test2.sh" and run test1.sh again. See the difference when test2.sh is sourced?

Eric
 
Old 11-01-2005, 04:17 PM   #10
Woodsman
Senior Member
 
Registered: Oct 2005
Distribution: Slackware 14.1
Posts: 3,482

Original Poster
Rep: Reputation: 534Reputation: 534Reputation: 534Reputation: 534Reputation: 534Reputation: 534
Quote:
It can even have unexpected results to end a script with the exit statement.
That all makes sense. I'm grokking. I was only curious if ending a script with exit 0 is a common programming practice and if so, why.

In a much related question to this scripting business, thanks to the previous information, I know how to parse text from a variable. But how do I assign text to a variable extracted through grep? I've been searching for an hour or so for this, but to no avail. Maybe the answer in obvious to all casual observers but me. What I want is:

VARIABLE=(grep -i "text to find" "file to search")

Additionally, how do I calculate the string length of a variable?

LENGTH=(count the number of characters in VARIABLE)

I imagine some kind of For-Do loop, but the syntax of all of this bashing is still new to me. If this info is covered in one of the primary bash guides, then just point me to the appropriate sections of those guides. Thanks again!
 
Old 11-01-2005, 04:23 PM   #11
Alien Bob
Slackware Contributor
 
Registered: Sep 2005
Location: Eindhoven, The Netherlands
Distribution: Slackware
Posts: 5,308

Rep: Reputation: Disabled
Like this:
Code:
VARIABLE=`grep -i "text to find" "file to search"`
and the length of a variable:
Code:
${#VARIABLE}
Cheers, Eric
 
Old 11-01-2005, 05:07 PM   #12
Woodsman
Senior Member
 
Registered: Oct 2005
Distribution: Slackware 14.1
Posts: 3,482

Original Poster
Rep: Reputation: 534Reputation: 534Reputation: 534Reputation: 534Reputation: 534Reputation: 534
Quote:
VARIABLE=`grep -i "text to find" "file to search"`
Ah! The infamous back ticks! Makes so much sense with only one example. Thank you!

Quote:
${#VARIABLE}
Works like a charm! Again, makes so much sense with only one example. Groovious!
 
Old 11-02-2005, 03:04 AM   #13
Alien Bob
Slackware Contributor
 
Registered: Sep 2005
Location: Eindhoven, The Netherlands
Distribution: Slackware
Posts: 5,308

Rep: Reputation: Disabled
By the way, a must-have for your bookmarks is this URL: the Advanced Bash-Scripting Guide

Cheers, Eric
 
Old 11-02-2005, 02:20 PM   #14
Woodsman
Senior Member
 
Registered: Oct 2005
Distribution: Slackware 14.1
Posts: 3,482

Original Poster
Rep: Reputation: 534Reputation: 534Reputation: 534Reputation: 534Reputation: 534Reputation: 534
Quote:
Code:
allowedchars="YyNn"
response=
while ! [[ "${response:0:1}" =~ "[$allowedchars]" ]] ; do
  read -er -p "Do you want to continue? (y/n): " response
done
This works great! However, I admit that I am perplexed by the absense of a simple CHOICE command. When I started writing this script the first thing I looked for was an equivalent CHOICE command. Unusual! Seems the 'nix world is otherwise full of these small one-task commands.

Quote:
By the way, a must-have for your bookmarks is this URL: the Advanced Bash-Scripting Guide
Agreed! Been there done that!

But I'm stuck on stinking dialup. Therefore I downloaded both the HTML and PDF versions so I can browse more conveniently.

I've provided technical writing services for two decades and I learned long ago that even the best of documentation is useless if one does not form the question that suits the style of the documentation. I think most of the answers provided in this thread, and in a few others I've posted recently, actually are documented in the three bash guides, but to a beginning basher who does not yet know the language and syntax of bash I was unable to find my solution in the guides until after all of you provided the necessary hints. And I'm grateful for that!

Yes, I could sit and actually read the entire guide, all of them, but as I'm sure many will agree, reading is not the same as doing. Actually writing a script paints one into a corner that necessitates asking specific questions, and that process far outpaces trying to read and sponge an entire document into memory!

I do not consider myself a noob at computers (been using them for more than two decades) or Slackware (been using for a year), but the entire 'nix environment is far too complex for anybody to master fully. For that reason alone, I'm grateful for all of you expert Slackers here at LQ. Thank you!

Oh, and FWIW, I now have some nice bash scripts thanks to all of the bite-size hints and answers provided in these threads. Again thank you all!

I only hope as time progresses that I too can provide some meaningful help to other people.

Last edited by Woodsman; 11-02-2005 at 02:49 PM.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Bash scripting vinoth.ilango Solaris / OpenSolaris 6 10-29-2004 04:41 AM
mask user input in a bash script PlatinumRik Linux - Software 1 06-15-2004 10:06 AM
BASH scripting; su to user, commands after dont execute Zero-0-Effect Programming 4 06-07-2004 11:09 AM
my mouse input is takes as keyboard input in BASH e1000 Slackware 5 12-08-2003 03:00 PM
User input using a BASH script... causticmtl Programming 5 07-13-2003 09:59 PM


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

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration