The standard-solution for bash, see:
https://askubuntu.com/questions/15853/how-can-a-script-check-if-its-being-run-as-root
which is:
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root"
exit 1
fi
does not work in dash, which is slowly becoming the standard-shell under Linux. How can the above be ported to dash?
Use id:
if [ "$(id -u)" -eq 0 ]; then
echo "I am root!"
fi
Or
#!/bin/sh
if [ "$(id -u)" -ne 0 ]; then
echo "This script must be run as root"
exit 1
fi
What I usually do is check for the capabilities I actually require, so that the script will also work correctly for a user who likes to run via an alternate privileged account (*BSD used to have toor for superuser with csh, which of course nobody in their right mind would want these days, but anyway).
test -w /usr/share/bin ||
{ echo "$0: /usr/share/bin not writable -- aborting" >&2; exit 1 }
Use the "id -u" command to get your current effective user id:
#!/bin/dash
MYUID=`id -u`
if [ "$MYUID" -eq 0 ]
then
echo "You are root"
else
echo "You are the non-root user with uid $MYUID"
fi
Related
I have a script and want to ask the user for some information, but the script cannot continue until the user fills in this information. The following is my attempt at putting a command into a loop to achieve this but it doesn't work for some reason:
echo "Please change password"
while passwd
do
echo "Try again"
done
I have tried many variations of the while loop:
while `passwd`
while [[ "`passwd`" -gt 0 ]]
while [ `passwd` -ne 0 ]]
# ... And much more
But I can't seem to get it to work.
until passwd
do
echo "Try again"
done
or
while ! passwd
do
echo "Try again"
done
To elaborate on #Marc B's answer,
$ passwd
$ while [ $? -ne 0 ]; do !!; done
Is nice way of doing the same thing that's not command specific.
You need to test $? instead, which is the exit status of the previous command. passwd exits with 0 if everything worked ok, and non-zero if the passwd change failed (wrong password, password mismatch, etc...)
passwd
while [ $? -ne 0 ]; do
passwd
done
With your backtick version, you're comparing passwd's output, which would be stuff like Enter password and confirm password and the like.
If anyone looking to have retry limit:
max_retry=5
counter=0
until $command
do
sleep 1
[[ counter -eq $max_retry ]] && echo "Failed!" && exit 1
echo "Trying again. Try #$counter"
((counter++))
done
You can use an infinite loop to achieve this:
while true
do
read -p "Enter password" passwd
case "$passwd" in
<some good condition> ) break;;
esac
done
while [ -n $(passwd) ]; do
echo "Try again";
done;
I am a beginner in bash scripting and I have created a bash script to add users and remove users on Linux. But since I am facing some issues with the script not really major issues but would be helpful if anyone could point me how to improve the script and the worst practice I am doing the script would be helpful
however the problem I have noticed is that the script takes -a to add a user -d to remove user and -h to get help the -a flag as 2 optional arguments -p for password and -s for shell so the command would be
./useradd.sh -a user -p password -s shell
this works as expected and the user is added to the system but the problem I am facing is that if I do not enter -a flag and specify the -s and -p flag the script is just exited I want to show a clear idea to the user why it exited and there is so many such errors I am assuming but I have not tested it out so much any help would be appreciated, so here is my script
#!/bin/bash
## checking if the user is privileged or not
if [[ $EUID != 0 ]]
then
echo "Script has to be ran as root or sudo"
echo "Aborting"
exit 101
fi
## creating help functions
function usage() {
echo "usage: ${0} -a <user> -p <password> -s <shell> | ${0} -d <user> | ${0} -h"
}
function help() {
echo "$0 - Script to add of remove users"
echo "-a - Add a new user"
echo " -p - Set password while creating user if not mentioned will not set any password by default"
echo " -s - Set a shell for the user default is /bin/bash if none specified"
echo "-a - Remove a user"
echo "-h - Print this help text"
}
if [[ "$#" -lt "1" ]]; then
echo "Argument has to be provided see $0 -h"
fi
shell=/bin/bash
password=$(openssl rand -base64 32)
while getopts :a:d:h opt; do
case $opt in
a) user=$OPTARG
while getopts :p:s: test
do
case $test in
p) password=$OPTARG;;
s) shell=$OPTARG;;
/?) echo "The provided flag is not identified see $0 -h"
exit;;
:) echo "$OPTARG requires arguments see $0 -h"
exit;;
esac
done
if [[ "$1" != "-a" ]]
then
echo "You have to specify username using -a flag see $0 -h"
fi
useradd -m $user -s $shell
echo "$user":"$password" | chpasswd
echo "The password for the $user is $password";;
d) userdel -f $OPTARG
if [[ $? == 0 ]]
then
echo "user has been removed"
else
echo "There was some error removing the user"
fi;;
h) help
exit;;
/?) echo "$OPTARG option not valid";;
:) echo "$OPTARG requires argument";;
esac
done
Please show your code! I usually process args with case ... in likes :
#!/bin/bash
while [[ $# -gt 0 ]]; do
case $1 in
"-a")
echo "-a is $2"
shift 2;;
"-d")
echo "-d is $2"
shift 2;;
esac
done
I have BBB based custom Embedded Linux based board with busybox shell(ash)
I have a situation where my script must run in background with following condition
There must only one instance of the script.
wrapper script need to know if script started successfully in background or not.
There is another wrapper script which starts and stops my script, wrapper script is as mentioned below.
#!/bin/sh
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
readonly TEST_SCRIPT_PATH="/home/testscript.sh"
readonly TEST_SCRIPT_LOCK_PATH="/var/run/${TEST_SCRIPT_PATH##*/}.lock"
start_test_script()
{
local pid_of_testscript=0
local status=0
#Run test script in background
"${TEST_SCRIPT_PATH}" &
#---------Now When this point is hit, lock file must be created.-----
if [ -f "${TEST_SCRIPT_LOCK_PATH}" ];then
pid_of_testscript=$(head -n1 ${TEST_SCRIPT_LOCK_PATH})
if [ -n "${pid_of_testscript}" ];then
kill -0 ${pid_of_testscript} &> /dev/null || status="${?}"
if [ ${status} -ne 0 ];then
echo "Error starting testscript"
else
echo "testscript start successfully"
fi
else
echo "Error starting testscript.sh"
fi
fi
}
stop_test_script()
{
local pid_of_testscript=0
local status=0
if [ -f "${TEST_SCRIPT_LOCK_PATH}" ];then
pid_of_testscript=$(head -n1 ${TEST_SCRIPT_LOCK_PATH})
if [ -n "${pid_of_testscript}" ];then
kill -0 ${pid_of_testscript} &> /dev/null || status="${?}"
if [ ${status} -ne 0 ];then
echo "testscript not running"
rm "${TEST_SCRIPT_LOCK_PATH}"
else
#send SIGTERM signal
kill -SIGTERM "${pid_of_testscript}"
fi
fi
fi
}
#Script starts from here.
case ${1} in
'start')
start_test_script
;;
'stop')
stop_test_script
;;
*)
echo "Usage: ${0} [start|stop]"
exit 1
;;
esac
Now actual script "testscript.sh" looks something like this,
#!/bin/sh
#Filename : testscript.sh
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
set -eu
LOCK_FILE="/var/run/${0##*/}.lock"
FLOCK_CMD="/bin/flock"
FLOCK_ID=200
eval "exec ${FLOCK_ID}>>${LOCK_FILE}"
"${FLOCK_CMD}" -n "${FLOCK_ID}" || exit 0
echo "${$}" > "${LOCK_FILE}"
# >>>>>>>>>>-----Now run the code in background---<<<<<<
handle_sigterm()
{
# cleanup
"${FLOCK_CMD}" -u "${FLOCK_ID}"
if [ -f "${LOCK_FILE}" ];then
rm "${LOCK_FILE}"
fi
}
trap handle_sigterm SIGTERM
while true
do
echo "do something"
sleep 10
done
Now in above script you can see "---Now run the code in background--" at that point I am sure that either lock file is successfully created or instance of this script is already running. So Then I can safely run other code in background and wrapper script can check for lockfile and find out if the process mentioned in the lock file is running or not.
can shellscript itself make it to run in background ?
if not is there a better way to meet all the conditions ?
I think you can look into job control built-in, specifically bg.
Job Control Commands
When processes say they background themselves, what they actually do is fork and exit the parent. You can do the same by running whichever commands, functions or statements you want with & and then exiting.
#!/bin/sh
echo "This runs in the foreground"
sleep 3
while true
do
sleep 10
echo "doing background things"
done &
I would like to check if a certain file exists on the remote host.
I tried this:
$ if [ ssh user#localhost -p 19999 -e /home/user/Dropbox/path/Research_and_Development/Puffer_and_Traps/Repeaters_Network/UBC_LOGS/log1349544129.tar.bz2 ] then echo "okidoke"; else "not okay!" fi
-sh: syntax error: unexpected "else" (expecting "then")
In addition to the answers above, there's the shorthand way to do it:
ssh -q $HOST [[ -f $FILE_PATH ]] && echo "File exists" || echo "File does not exist";
-q is quiet mode, it will suppress warnings and messages.
As #Mat mentioned, one advantage of testing like this is that you can easily swap out the -f for any test operator you like: -nt, -d, -s etc...
Test Operators: http://tldp.org/LDP/abs/html/fto.html
Here is a simple approach:
#!/bin/bash
USE_IP='-o StrictHostKeyChecking=no username#192.168.1.2'
FILE_NAME=/home/user/file.txt
SSH_PASS='sshpass -p password-for-remote-machine'
if $SSH_PASS ssh $USE_IP stat $FILE_NAME \> /dev/null 2\>\&1
then
echo "File exists"
else
echo "File does not exist"
fi
You need to install sshpass on your machine to work it.
Can't get much simpler than this :)
ssh host "test -e /path/to/file"
if [ $? -eq 0 ]; then
# your file exists
fi
As suggested by dimo414, this can be collapsed to:
if ssh host "test -e /path/to/file"; then
# your file exists
fi
one line, proper quoting
ssh remote_host test -f "/path/to/file" && echo found || echo not found
You're missing ;s. The general syntax if you put it all in one line would be:
if thing ; then ... ; else ... ; fi
The thing can be pretty much anything that returns an exit code. The then branch is taken if that thing returns 0, the else branch otherwise.
[ isn't syntax, it's the test program (check out ls /bin/[, it actually exists, man test for the docs – although can also have a built-in version with different/additional features.) which is used to test various common conditions on files and variables. (Note that [[ on the other hand is syntax and is handled by your shell, if it supports it).
For your case, you don't want to use test directly, you want to test something on the remote host. So try something like:
if ssh user#host test -e "$file" ; then ... ; else ... ; fi
Test if a file exists:
HOST="example.com"
FILE="/path/to/file"
if ssh $HOST "test -e $FILE"; then
echo "File exists."
else
echo "File does not exist."
fi
And the opposite, test if a file does not exist:
HOST="example.com"
FILE="/path/to/file"
if ! ssh $HOST "test -e $FILE"; then
echo "File does not exist."
else
echo "File exists."
fi
ssh -q $HOST [[ -f $FILE_PATH ]] && echo "File exists"
The above will run the echo command on the machine you're running the ssh command from. To get the remote server to run the command:
ssh -q $HOST "[[ ! -f $FILE_PATH ]] && touch $FILE_PATH"
Silent check if file exist and perform if not
if ! ssh $USER#$HOST "test -e file.txt" 2> /dev/null; then
echo "File not exist"
fi
You can specify the shell to be used by the remote host locally.
echo 'echo "Bash version: ${BASH_VERSION}"' | ssh -q localhost bash
And be careful to (single-)quote the variables you wish to be expanded by the remote host; otherwise variable expansion will be done by your local shell!
# example for local / remote variable expansion
{
echo "[[ $- == *i* ]] && echo 'Interactive' || echo 'Not interactive'" |
ssh -q localhost bash
echo '[[ $- == *i* ]] && echo "Interactive" || echo "Not interactive"' |
ssh -q localhost bash
}
So, to check if a certain file exists on the remote host you can do the following:
host='localhost' # localhost as test case
file='~/.bash_history'
if `echo 'test -f '"${file}"' && exit 0 || exit 1' | ssh -q "${host}" sh`; then
#if `echo '[[ -f '"${file}"' ]] && exit 0 || exit 1' | ssh -q "${host}" bash`; then
echo exists
else
echo does not exist
fi
I wanted also to check if a remote file exist but with RSH. I have tried the previous solutions but they didn't work with RSH.
Finally, I did I short function which works fine:
function existRemoteFile ()
{
REMOTE=$1
FILE=$2
RESULT=$(rsh -l user $REMOTE "test -e $FILE && echo \"0\" || echo \"1\"")
if [ $RESULT -eq 0 ]
then
return 0
else
return 1
fi
}
On CentOS machine, the oneliner bash that worked for me was:
if ssh <servername> "stat <filename> > /dev/null 2>&1"; then echo "file exists"; else echo "file doesnt exits"; fi
It needed I/O redirection (as the top answer) as well as quotes around the command to be run on remote.
This also works :
if ssh user#ip "[ -s /path/file_name ]" ;then
status=RECEIVED ;
else
status=MISSING ;
fi
#its simple
if [[ "`ssh -q user#hostname ls /dir/filename.abc 2>dev/null`" == "/dir/filename.abc" ]]
then
echo "file exists"
else
echo "file not exists"
fi
I'm trying to access out Linux server through Putty but for some reason after a somewhat successful login it just throws a "/bin/bash no such file or directory" then Putty closes.
Contents of bashrc:
# /etc/bashrc
# System wide functions and aliases
# Environment stuff goes in /etc/profile
# By default, we want this to get set.
# Even for non-interactive, non-login shells.
if [ $UID -gt 99 ] && [ "`id -gn`" = "`id -un`" ]; then
umask 002
else
umask 022
fi
# are we an interactive shell?
if [ "$PS1" ]; then
case $TERM in
xterm*)
if [ -e /etc/sysconfig/bash-prompt-xterm ]; then
PROMPT_COMMAND=/etc/sysconfig/bash-prompt-xterm
else
PROMPT_COMMAND='echo -ne "\033]0;${USER}#${HOSTNAME%%.*}:${PWD/#$HOME/~}"; echo -ne "\007"'
fi
;;
screen)
if [ -e /etc/sysconfig/bash-prompt-screen ]; then
PROMPT_COMMAND=/etc/sysconfig/bash-prompt-screen
else
PROMPT_COMMAND='echo -ne "\033_${USER}#${HOSTNAME%%.*}:${PWD/#$HOME/~}"; echo -ne "\033\\"'
fi
;;
*)
[ -e /etc/sysconfig/bash-prompt-default ] && PROMPT_COMMAND=/etc/sysconfig/bash-prompt-default
;;
esac
# Turn on checkwinsize
shopt -s checkwinsize
[ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u#\h \W]\\$ "
fi
if ! shopt -q login_shell ; then # We're not a login shell
# Need to redefine pathmunge, it get's undefined at the end of /etc/profile
pathmunge () {
if ! echo $PATH | /bin/egrep -q "(^|:)$1($|:)" ; then
if [ "$2" = "after" ] ; then
PATH=$PATH:$1
else
PATH=$1:$PATH
fi
fi
}
# Only display echos from profile.d scripts if we are no login shell
# and interactive - otherwise just process them to set envvars
for i in /etc/profile.d/*.sh; do
if [ -r "$i" ]; then
if [ "$PS1" ]; then
. $i
else
. $i >/dev/null 2>&1
fi
fi
done
unset i
unset pathmunge
fi
# vim:ts=4:sw=4
What could be causing this?
Thanks!
Well bash is more than likely located at a different location on this linux box to /bin/bash
I've found this to be the case on different boxes and I've changed my .profile script in my home directory to not directly execute bash, could be a solution in your case. So when you log in you stay in the bourne shell, and then go into the bash shell only if you explicitly type bash.
Check your /etc/ssh/sshd_config to make sure that you don't have a chroot directory set. If you do, you will need to either create a bin directory in the chroot directory and either copy or link the necessary binaries into that directory.
Or you could always comment that line out in the config.
Either way, restart sshd and test.