How do I determine if a shell script is running with root permissions? - shell

I've got a script I want to require be run with su privileges, but the interesting scripted command that will fail comes very late in the script, so I'd like a clean test up front to determine if the scrip will fail without SU capabilities.
What is a good way to do this for bash, sh, and/or csh?

bash/sh:
#!/usr/bin/env bash
# (Use #!/bin/sh for sh)
if [ `id -u` = 0 ] ; then
echo "I AM ROOT, HEAR ME ROAR"
fi
csh:
#!/bin/csh
if ( `id -u` == "0" ) then
echo "I AM ROOT, HEAR ME ROAR"
endif

You might add something like that at the beginning of your script:
#!/bin/sh
ROOTUID="0"
if [ "$(id -u)" -ne "$ROOTUID" ] ; then
echo "This script must be executed with root privileges."
exit 1
fi

Related

Bash script not running in Ubuntu

I'm getting started with bash scripting and made this little script following along a short guide but for some reason when I run the script with sh myscript I get
myscript: 5: myscript: 0: not found running on ubuntu 12.04
here is my script below I should at least see the echo message if no args are set:
#!/bin/bash
#will do something
name=$1
username=$2
if (( $# == 0 ))
then
echo "##############################"
echo "myscript [arg1] [arg2]"
echo "arg1 is your name"
echo "and arg2 is your username"
fi
var1="Your name is ${name} and your username is ${username}"
`echo ${var1} > yourname.txt`
`echo ${var1} > yourname.txt`
Get rid of the backticks.
echo ${var1} > yourname.txt
...for some reason when I run the script with sh myscript...
Don't run it that way. Make the script executable and run it directly
chmod +x myscript
./script
(or run with bash myscript explicitly).
It looks like that expression will work in bash but not in sh. As others pointed out change it to executable, make sure your shebang line is using bash and run it like this:
./myscript
If you want to run it with sh then it is complaining about line 5. Change it to this and it will work in /bin/sh.
if [ $# -ne 0 ]
Check out the man page for test.
Also you don't need the backticks on this line:
echo ${var1} > yourname.txt

Unix utility which executes a command and tests its exit status

I am writing automated tests for the Gasoline, an OCaml library implementing application templates. Applications are expected to fail with a prescribed exit code in certain circumstances, like exit code 64 EXIT_USAGE when the application is called with an ill-formed command line:
% ./punishment.byte -x
punishment.byte: illegal option -- x
Usage: punishment.byte [-n number] [-p paragraph] [-c configfile]
Exit 64
Is there a standard Unix utility that can be used to run the subcommand ./punishment.byte -x and exit with status code 0 if the subcommand exited with status code 64? Something like
% expect_status 64 ./punishment.byte -x
punishment.byte: illegal option -- x
Usage: punishment.byte [-n number] [-p paragraph] [-c configfile]
Exit 0
As I am using a Makefile to orchestrate the tests, a legible statement such as expect_status 64 ./punishment.byte -x would be nice to have.
Notes
The Exit line in console interaction examples is informative and not part of the output.
I am well aware that I can write such a tool and how to do it, I just want to be sure there is no standard command doing that already.
The answer to your question is no. There is no standard utility on *nix systems for running a command and testing its exit code against a specific value. Probably because it's trivial to write one yourself.
I'm guessing from the % in your code that you're using zsh. If you're actually using csh (or tcsh), then things work differently.
That said, you can easily write a shell function to do this:
expect_status() {
local expected=$1
shift
"$#"
(( $? == expected ))
}
But that will run the command inside your current shell environment, which may have side effects you don't want. It would probably be better realized as a script - just save it somewhere in your $PATH with the filename expect_status and give it read and execute permission:
#!/bin/bash
expected=$1
shift
"$#"
(( $? == expected ))
Or, eschewing bashisms:
#!/bin/sh
expected=$1
shift
${1+"$#"}
[ $? -eq $expected ]
As suggested, you can check exit code of last command execution by referencing shell variable "$?".
$ ls -bogusOption
ls: invalid option -- 'O'
Try 'ls --help' for more information.
$ echo $?
2
shell can be used as utility to test exit code. say,
$ cat test.sh
#!/usr/bin/env bash
echo "executing bogus option"
ls -bogusOption
if [ "$?" -eq "0" ]; then
echo "command succeeded."
else
echo "command failed"
fi
$ bash -xv ./test.sh
#!/usr/bin/env bash
echo "executing bogus option"
+ echo 'executing bogus option'
executing bogus option
ls -bogusOption
+ ls -bogusOption
ls: invalid option -- 'O'
Try 'ls --help' for more information.
if [ "$?" -eq "0" ]; then
echo "command succeeded."
else
echo "command failed"
fi
+ '[' 2 -eq 0 ']'
+ echo 'command failed'
command failed
Well, in a sense, there is a standard utility: the shell itself:
command1 && command2
The above will only execute command2 if the exit code of command1 is 0. Alternatively, this:
command1 || command2
will only run command2 if the exit code of command1 was not 0.
To check for a specific exit status, you would use $? as described in the other answers:
command; [ "$?" -eq 64 ] && command2
So, the functionality you're looking for is essentially built directly into the shell and, therefore, you won't find a utility designed to do this.

Simple bash script for starting application silently

Here I am again. Today I wrote a little script that is supposed to start an application silently in my debian env.
Easy as
silent "npm search 1234556"
This works but not at all.
As you can see, I commented the section where I have some troubles.
This line:
$($cmdLine) &
doesn't hide application output but this one
$($1 >/dev/null 2>/dev/null) &
works perfectly. What am I missing? Many thanks.
#!/bin/sh
# Daniele Brugnara
# October, 2013
# Silently exec a command line passed as argument
errorsRedirect=""
if [ -z "$1" ]; then
echo "Please, don't joke me..."
exit 1
fi
cmdLine="$1 >/dev/null"
# if passed a second parameter, errors will be hidden
if [ -n "$2" ]; then
cmdLine="$cmdLine 2>/dev/null"
fi
# not working
$($cmdLine) &
# works perfectly
#$($1 >/dev/null 2>/dev/null) &
With the use of evil eval following script will work:
#!/bin/sh
# Silently exec a command line passed as argument
errorsRedirect=""
if [ -z "$1" ]; then
echo "Please, don't joke me..."
exit 1
fi
cmdLine="$1 >/dev/null"
# if passed a second parameter, errors will be hidden
if [ -n "$2" ]; then
cmdLine="$cmdLine 2>&1"
fi
eval "$cmdLine &"
Rather than building up a command with redirection tacked on the end, you can incrementally apply it:
#!/bin/sh
if [ -z "$1" ]; then
exit
fi
exec >/dev/null
if [ -n "$2" ]; then
exec 2>&1
fi
exec $1
This first redirects stdout of the shell script to /dev/null. If the second argument is given, it redirects stderr of the shell script too. Then it runs the command which will inherit stdout and stderr from the script.
I removed the ampersand (&) since being silent has nothing to do with running in the background. You can add it back (and remove the exec on the last line) if it is what you want.
I added exec at the end as it is slightly more efficient. Since it is the end of the shell script, there is nothing left to do, so you may as well be done with it, hence exec.
& means that you're doing sort of multitask whereas
1 >/dev/null 2>/dev/null
means that you redirect the output to a sort of garbage and that's why you don't see anything.
Furthermore cmdLine="$1 >/dev/null" is incorrect, you should use ' instead of " :
cmdLine='$1 >/dev/null'
you can build your command line in a var and run a bash with it in background:
bash -c "$cmdLine"&
Note that it might be useful to store the output (out/err) of the program, instead of trow them in null.
In addition, why do you need errorsRedirect??
You can even add a wait at the end, just to be safe...if you want...
#!/bin/sh
# Daniele Brugnara
# October, 2013
# Silently exec a command line passed as argument
[ ! $1 ] && echo "Please, don't joke me..." && exit 1
cmdLine="$1>/dev/null"
# if passed a second parameter, errors will be hidden
[ $2 ] && cmdLine+=" 2>/dev/null"
# not working
echo "Running \"$cmdLine\""
bash -c "$cmdLine" &
wait

check isatty in bash

I want my shell to detect if human behavior, then show the prompt.
So, assume the file name is test.bash
#!/bin/bash
if [ "x" != "${PS1:-x}" ] ;then
read -p "remove test.log Yes/No" x
[ "$x" = "n" ] && exit 1
fi
rm -f test.log
But, I found it can not work if I haven't set PS1. Is there better method?
my test methods:
./test.bash # human interactive
./test.bash > /tmp/test.log # stdout in batch mode
ls | ./test.bash # stdin in batch mode
to elaborate, I would try
if [ -t 0 ] ; then
# this shell has a std-input, so we're not in batch mode
.....
else
# we're in batch mode
....
fi
I hope this helps.
From help test:
-t FD True if FD is opened on a terminal.
You could make use of the /usr/bin/tty program:
if tty -s
then
# ...
fi
I admit that I'm not sure how portable it is, but it's at least part of GNU coreutils.
Note that in bash scripts (see the test expr entry in man bash), it is not necessary to use the beefy && and || shell operators to combine two separate runs of the [ command, because the [ command has its own built-in and -a and or -o operators that let you compose several simpler tests into a single outcome.
So, here is how you can implement the test that you asked for — where you flip into batch mode if either the input or the output has been redirected away from the TTY — using a single invocation of [:
if [ -t 0 -a -t 1 ]
then
echo Interactive mode
else
echo Batch mode
fi

Shell scripting: die on any error

Suppose a shell script (/bin/sh or /bin/bash) contained several commands. How can I cleanly make the script terminate if any of the commands has a failing exit status? Obviously, one can use if blocks and/or callbacks, but is there a cleaner, more concise way? Using && is not really an option either, because the commands can be long, or the script could have non-trivial things like loops and conditionals.
With standard sh and bash, you can
set -e
It will
$ help set
...
-e Exit immediately if a command exits with a non-zero status.
It also works (from what I could gather) with zsh. It also should work for any Bourne shell descendant.
With csh/tcsh, you have to launch your script with #!/bin/csh -e
May be you could use:
$ <any_command> || exit 1
You can check $? to see what the most recent exit code is..
e.g
#!/bin/sh
# A Tidier approach
check_errs()
{
# Function. Parameter 1 is the return code
# Para. 2 is text to display on failure.
if [ "${1}" -ne "0" ]; then
echo "ERROR # ${1} : ${2}"
# as a bonus, make our script exit with the right error code.
exit ${1}
fi
}
### main script starts here ###
grep "^${1}:" /etc/passwd > /dev/null 2>&1
check_errs $? "User ${1} not found in /etc/passwd"
USERNAME=`grep "^${1}:" /etc/passwd|cut -d":" -f1`
check_errs $? "Cut returned an error"
echo "USERNAME: $USERNAME"
check_errs $? "echo returned an error - very strange!"

Resources