I'm new to Linux and am trying to create a simple program that checks if a user exists, if exists - exits the terminal, if not - creates it. I think I've done everything except exiting the terminal.
This is my code so far:
#!/bin/bash
user_name=newUser
if [ $(getent passwd $user_name) ]
then
echo "User $user_name already exists!"
exit
else
echo "The user $user_name doesn't exist and will be added"
sudo useradd -d /home/mint/newUser $user_name
fi
edit: As I said i'm new to Linux. Can someone edit my code and post it, I need to add it to a script, maybe i can close it with while function?
The exit command simply exits the current script. If you want to exit the terminal, you need to exit (or otherwise terminate) the program which is running in that terminal.
A common way to accomplish this is to make the process which wants to exit run as a function in your interactive shell.
add_user () { /path/to/your/script "$#" || exit; }
In this case, though, I would simply advise you to keep your script as is, and leave it to the user to decide whether or not they want to close their terminal.
By the way, the construct
if [ $(command) ]
will be true if the output from command is a non-empty string. The correct way to check the exit code from command is simply
if command
possibly with output redirection if you don't want the invoking user to see any output from command.
The function above also requires your scripit to exit with an explicit error; probably change it to exit 1 to explicitly communicate an error condition back to the caller.
#!/bin/bash
# First parameter is name of user to add
user_name=$1
# Quote variable; examine exit code
if getent passwd "$user_name" >/dev/null 2>&1
then
# Notice addition of script name and redirect to stderr
echo "$0: User $user_name already exists!" >&2
# Explicitly exit with nonzero exit code
exit 1
else
# script name & redirect as above
echo "$0: The user $user_name doesn't exist and will be added" >&2
# Quote argument
sudo useradd -d /home/mint/newUser "$user_name"
fi
This has been answered on askubuntu.com. I will summarise here:
In your script, as you may have noticed, exit will only exit the current script.
A user-friendly way to achieve what you're after is to use the exit command to set a suitable return code and call your script like ./<script> && exit.
If you really want the hard way, use
kill -9 $PPID
which will attempt to kill the enclosing process.
Related
In the shell script, I want to do that
if the shell script failed ( exited with non zero value), then before exiting the process, do something.
How could I insert such a if statement block in my shell script.
Is that feasible?
For example,
set -e
echo $password > confidential.txt
rm <file-that-does-not-exist>
rm confidential.txt
I want to make sure that the confidential.txt is made sure to be removed anyways
Use the trap command:
trap 'if [ $? -ne 0 ]; then echo failed; fi' EXIT
The EXIT trap is run when the script exits, and $? contains the status of the last command before it exited.
Note that a shell script's exit status is the status of the last command that it executed. So in your script, it will be the status of
rm confidential.txt
not the error from
rm filethatdoesnotexist
Unless you use set -e in the script, which makes it exit as soon as any command gets an error.
Use trap with the EXIT pseudo signal:
remove_secret () {
rm -f /path/to/confidential.txt
}
trap remove_secret EXIT
You probably don't want the file to remain if the script exits with 0, so EXIT happens regardless of the exit code.
Note that without set -e, rm on a non-existent file doesn't stop the script.
Assuming you're on Linux (or another operating system with /proc/*/fd), you have an even better option: Delete confidential.txt before putting the password into it at all.
That can look something like the following:
exec 3<>confidential.txt
rm -f -- confidential.txt
printf '%s\n' "$password" >&3
...and then, to read from that deleted file:
cat "/proc/$$/fd/3" ## where $$ is the PID of the shell that ran the exec command above
Because the file is already deleted, it's guaranteed to be eligible for garbage collection by your filesystem the moment your script (or the last program it started inheriting its file descriptors) exits or is killed, even if it's killed in a way that doesn't permit traps or signal processing to take place.
I want to use flock to make sure only once instance of script is running at any given time.
Script skeleton looks like this:
ME=`basename "$0"`;
LOCK="/tmp/${ME}.LCK";
exec 8>$LOCK;
if flock -n -x 8; then
do things
if [ condition ]; then
/path/asterisk_restart.sh
fi
else
echo "$(date) script already running >> $log_file"
fi
Now the script /path/asterisk_restart.sh do many things, but in the end asterisk is stopped and last command is service asterisk start
The problem is this: as file handles and locks are shared across fork()/exec(), 8 filehandle remained locked in asterisk process, so the script will not run again once /path/asterisk_restart.sh is executed (and asterisk are not stopped/restarted by other means outside this script)
So my approach is to start sub-shell and close 8 file handle just before executing /path/asterisk_restart.sh.
It looks like this:
ME=`basename "$0"`;
LOCK="/tmp/${ME}.LCK";
exec 8>$LOCK;
if flock -n -x 8; then
do things
if [ condition ]; then
(
exec 8>&-
/path/asterisk_restart.sh
)
fi
else
echo "$(date) script already running >> $log_file"
fi
Is this a sound approach?
To prevent scripts against parallel run, I would suggest something like this.
if mkdir $LockDir; then
echo "Locking succeeded" >&2
# Your script here.
rm -f $LockDir
else
echo "Lock failed - exit" >&2
exit 1
fi
Using a directory instead of a file is better because mkdir is an atomic operation and hence would eliminate the race condition.
Also don't put your LockDir inside /tmp. If it gets removed, the lock is gone.
The only problem with the above implementation is that it does not work when the LockDir gets removed by some other script.
inside of my script I need to run two scripts as another user, so I used the following line:
su otherUser -c "firstScript;secondScript;status=$?"
echo "returning $status"
return $status
The problem is that $status will always return 0.I did test with secondScript failing (wrong argument). Not sure if it's because I exited otherUser or if the $status is actually the result of the su command. Any suggestions?!
You need to capture status inside your outer shell, not in the inner shell invoked by su; otherwise, the captured value is thrown away as soon as that inner shell exits.
This is made much easier because su passes through the exit status of the command it runs -- if that command exits with a nonzero status, so will su.
su otherUser -c 'firstScript; secondScript'; status=$?
echo "returning $status"
return $status
Note that this only returns the exit status of secondScript (as would your original code have done, were it working correctly). You might think about what you want to do if firstScript fails.
Now, it's a little more interesting if you only want to return the exit code of firstScript; in that case, you need to capture the exit status in both shells:
su otherUser -c 'firstScript; status=$?; secondScript; exit $status'); status=$?
echo "returning $status"
return $status
If you want to run secondScript only if firstScript succeeds, and return a nonzero value if either of them fails, it becomes easy again:
su otherUser -c 'firstScript && secondScript'); status=$?
echo "returning $status"
return $status
I need to exit from the current session and I am using the following code:
read -p "Do you want to start a new session? [Y/N] " usr_session
if [ "$usr_session" == "y" ] || [ "$usr_session" == "Y" ]; then
echo -e "`date`\t\t Exiting...\n You will need to login back...\n" >> $LOG_FILE
echo -e "Exiting...\n You will need to login back...\n"
sleep 5
curr_usr=`whoami`
pkill -9 -u $curr_usr
elif [ "$usr_session" == "n" ] || [ "usr_session" == "N" ]; then
echo -e "You are still in the same session.\n"
else
echo "Invalid input"
fi
Is there a better approach to perform the same but in more graceful manner? I feel the killing the current user process might not be safe. Any suggestions are really appreciated.
Thanks in advance.
Consider using logout.
(If you don't care to immediately terminate all running processes, including background jobs)
You could send a "softer" signal first instead of -9, to give time for the processes to shut down gracefully, then only send -9 to the processes that won't exit.
logout will work only if you are able to run this script as part of the login script (such as bashrc), not if it's run in a subshell. Alternatively (with the same effect), run the script with exec script_name from the login shell.
Another idea is to kill -HUP $PPID, assuming that the script is always run directly as a subshell of the login shell. This will signal the parent shell (the login shell) to end the session.
you could write a wrapper script and then source in , for example
file : wrap1.sh
./myscript.sh
if [ $? != 0 ];then
exit
fi
replace kill with exit 1 and from main session :
source wrap1.sh
I have a daemon I have written using Python. When it is running, it has a PID file located at /tmp/filename.pid. If the daemon isn't running then PID file doesn't exist.
On Linux, how can I check to ensure that the PID file exists and if not, execute a command to restart it?
The command would be
python daemon.py restart
which has to be executed from a specific directory.
[ -f /tmp/filename.pid ] || python daemon.py restart
-f checks if the given path exists and is a regular file (just -e checks if the path exists)
the [] perform the test and returns 0 on success, 1 otherwise
the || is a C-like or, so if the command on the left fails, execute the command on the right.
So the final statement says, if /tmp/filename.pid does NOT exist then start the daemon.
test -f filename && daemon.py restart || echo "File doesn't exists"
If it is bash scripting you are wondering about, something like this would work:
if [ ! -f "$FILENAME" ]; then
python daemon.py restart
fi
A better option may be to look into lockfile
The other answers are fine for detecting the existence of the file. However for a complete solution you probably should check that the PID in the pidfile is still running, and that it's your program.
Another approach to solving the problem is a script that ensures that your daemon "stays" alive...
Something like this (note: signal handling should be added for proper startup/shutdown):
$PIDFILE = "/path/to/pidfile"
if [ -f "$PIDFILE" ]; then
echo "Pid file exists!"
exit 1
fi
while true; do
# Write it's own pid file
python your-server.py ;
# force removal of pid in case of unexpected death.
rm -f $PIDFILE;
# sleep for 2 seconds
sleep 2;
done
In this way, the server will stay alive even if it dies unexpectedly.
You can also use a ready solution like Monit.
ls /tmp/filename.pid
It returns true if file exists. Returns false if file does not exist.