I've had great results with this combination:
ps -p $$ | awk '$1 != "PID" {print $(NF)}'
On Tru64 (OSF/1), the output has parentheses around the shell. Tack on tr -d '()'
to remove them.
ps -p $$ | awk '$1 != "PID" {print $(NF)}' | tr -d '()'
Appears to works on all shells, on Solaris 10 and RHEL 5.7 / 6.4. Didn't test other distros such as Debian, Ubuntu, or Mint, but I would think they should all work the same; I also have no idea if FreeBSD would work.
I think the easiest way would be to wrap the prompting code into a function, and then drop it into an until
loop.
Since all you need really is to call the function until it succeeds, you can put the noop command ":
" in the until loop.
Something like this:
#!/bin/bash
getgender() {
read -p "What is the gender of the user? (male/female): " gender
case "$gender" in
m|M)
grouptoaddto="boys"
return 0
;;
f|F)
grouptoaddto="girls"
return 0
;;
*)
printf %s\\n "Please enter 'M' or 'F'"
return 1
;;
esac
}
until getgender; do : ; done
sudo usermod -a -G "$grouptoaddto" "$username"
The point here is the function called with until
, so it is repeatedly called until it succeeds. The case switch within the function is just an example.
Simpler example, without using a function:
while [ -z "$groupname" ]; do
read -p "What gender is the user?" answer
case "$answer" in
[MmBb]|[Mm]ale|[Bb]oy) groupname="boys" ;;
[FfGg]|[Ff]emale|[Gg]irl) groupname="girls" ;;
*) echo "Please choose male/female (or boy/girl)" ;;
esac
done
sudo usermod -a -G "$groupname" "$username"
In this last example, I'm using the -z
switch to the [
(test) command, to continue the loop as long as the "groupname" variable has zero length.
The keynote is the use of while
or until
.
To translate this last example into human readable pseudocode:
While groupname is empty,
ask user for gender.
If he answers with one letter "m" or "B",
or the word "Male" or "boy",
set the groupname as "boys".
If she answers with one letter "F" or "g",
or the word "female" or "Girl",
set the groupname as "girls".
If he/she answers anything else, complain.
(And then repeat, since groupname is still empty.)
Once you have groupname populated,
add the user to that group.
Yet another example, without the groupname
variable:
while true; do
read -p "What gender is the user?" answer
case "$answer" in
[MmBb]|[Mm]ale|[Bb]oy)
sudo usermod -a -G boys "$username"
break
;;
[FfGg]|[Ff]emale|[Gg]irl)
sudo usermod -a -G girls "$username"
break
;;
*) echo "Please choose male/female (or boy/girl)" ;;
esac
done
Best Answer
Abstract
To reverse a
set -x
just execute aset +x
. Most of the time, the reverse of an stringset -str
is the same string with a+
:set +str
.In general, to restore all (read below about bash
errexit
) shell options (changed withset
command) you could do (also read below about bashshopt
options):Should be enough, but bash has two groups of options accessed via
set
(orshopt -po
) and some others accessed viashopt -p
. Also, bash doesn't preserveset -e
(errexit) on entering subshells. Note that the list of options that results from expanding$-
might not be valid to re-enter in a shell.To capture the whole present state (in bash) use:
Or, if you don't mind setting the
inherit_errexit
flag (and your bash is ≥4.4):Longer Description
bash
This command:
is used to generate an executable string that reflects the state of the option(s). The
p
flag means print, and theo
flag specifies that we are asking about option(s) set by theset
command (as opposed to option(s) set only by theshopt
command). You can assign this string to a variable, and execute the variable at the end of your script to restore the initial state.This solution also works for multiple options simultaneously:
Adding
set +vx
avoids the printing of a long list of options.If you don’t list any option names,
it gives you the values of all (set) options. And, if you leave out the
o
flag, you can do the same things withshopt
options:If you need to test whether a
set
option is set, the most idiomatic (Bash) way to do it is:which is better than the other two similar tests:
[[ $- =~ x ]]
[[ $- == *x* ]]
With any of the tests, this works:
Here’s how to test the state of a
shopt
option:POSIX
A simple, POSIX-compliant solution to store all
set
options is:which is described in the POSIX standard as:
So, simply:
will preserve values for all options set using the
set
command (in some shells).Again, restoring the options to their original values is a matter of executing the variable:
This is exactly equivalent to using Bash's
shopt -po
. Note that it will not cover all possible Bash options, as some of those are set (only) byshopt
.bash special case
There are many other shell options listed with
shopt
in bash:Those could be appended to the variable set above and restored in the same way:
bash's
set -e
special caseIn bash, the value of
set -e
(errexit
) is reset inside sub-shells, that makes it difficult to capture its value withset +o
inside a $(…) sub-shell.As a workaround, use:
Or (if it doesn't contradict your goals and your bash supports it) you can use the
inherit_errexit
option.Note: each shell has a slightly different way to build the list of options that are set or unset (not to mention different options that are defined), so the strings are not portable between shells, but are valid for the same shell.
zsh special case
zsh
also works correctly (following POSIX) since version 5.3. In previous versions it followed POSIX only partially withset +o
in that it printed options in a format that was suitable for reinput to the shell as commands, but only for set options (it didn't print un-set options).mksh special case
The mksh (and by consequence lksh) is not yet (MIRBSD KSH R54 2016/11/11) able to do this. The mksh manual contains this: