I am a beginner and trying to write a script that takes a config file (example below) and sets the rights for the users, if that user or group doesn´t exist, they get added.
For every line in the file, I am cutting out the user or the group and check if they exist.
Right now I only check for users.
#!/bin/bash
function SetRights()
{
if [[ $# -eq 1 && -f $1 ]]
then
for line in $1
do
var1=$(cut -d: -f2 $line)
var2=$(cat /etc/passwd | grep $var1 | wc -l)
if [[ $var2 -eq 0 ]]
then
sudo useradd $var1
else
setfacl -m $line
fi
done
else
echo Enter the correct path of the configuration file.
fi
}
SetRights $1
The config file looks like this:
u:TestUser:- /home/temp
g:TestGroup:rw /home/temp/testFolder
u:TestUser2:r /home/temp/1234.txt
The output:
grep: TestGroup: No such file or directory
grep: TestUser: No such file or directory
"The useradd help menu"
If you could give me a hint what I should look for in my research, I would be very grateful.
Is it possible to reset var1 and var2? Using unset didn´t work for me and I couldn´t find variables could only be set once.
It's not clear how you are looping over the contents of the file -- if $1 contains the file name, you should not be seeing the errors you report.
But anyway, here is a refactored version which hopefully avoids your problems.
# Avoid Bash-only syntax for function definition
SetRights() {
# Indent function body
# Properly quote "$1"
if [[ $# -eq 1 && -f "$1" ]]
then
# Read lines in file
while read -r acl file
do
# Parse out user
user=${acl#*:}
user=${user%:*}
# Avoid useless use of cat
# Anchor regex correctly
if ! grep -q "^$user:" /etc/passwd
then
# Quote user
sudo useradd "$user"
else
setfacl -m "$acl" "$file"
fi
done <"$1"
else
# Error message to stderr
echo Enter the correct path of the configuration file. >&2
# Signal failure to the caller
return 1
fi
}
# Properly quote argument
SetRights "$1"
I'd like to use notify-send from within a bash script that is running in the background to inform the user about the progress of the script. More specifically this is a script that automagically runs when a USB flash drive is inserted and runs a scan with ClamAV.
Specifically at line 30 and line 66. So far, I'm not having any luck. Can someone give me some advice/help? Thanks.
#!/bin/bash
#doOnUSBinsert_0.2.sh
#Author : Totti
# Make it executable by running 'sudo chmod x doOnUSBinsert_0.2.sh'
if ! [ -f /etc/udev/rules.d/80-doOnUSBinsert.rules ]
then # rule not added
cp "$0" /usr/bin/doOnUSBinsert
chmod u x /usr/bin/doOnUSBinsert
# echo 'SUBSYSTEM=="usb", ACTION=="add", RUN ="/path/to/script.sh"' | sudo tee /etc/udev/rules.d/80-clamscan.rules
echo 'SUBSYSTEM=="usb", ACTION=="add", RUN ="/usr/bin/doOnUSBinsert & "' | tee /etc/udev/rules.d/80-doOnUSBinsert.rules
if [ $? -eq 0 ]
then
echo 'Rule Successfully added. See file "/usr/bin/doOnUSBinsert" if you wish to edit the command'
exit 0
else
echo 'ERROR while adding rule'
exit 1
fi
fi
lfile="/tmp/doOnUSBinsert.log" # udev
lfile2="/tmp/clamscanFromUdev.log" # clamscan
lfile3="/tmp/doOnUSBinsert_mount.log" # mount
notify-send "USB SCAN ON INSERT" "Currently scanning with ClamAV"
main ()
{
sleep 12 # let the partitions to mount
#cat /proc/$$/environ | tr '�' 'n' >> /tmp/udevEnvirn.txt
echo "found $ID_SERIAL" >> "$lfile"
cat /etc/mtab | grep "^$part_c" >> "$lfile.3"
if [ "$ID_SERIAL"x = 'x' ]
then
echo "Exiting on empty ID_SERIAL" >> "$lfile"
exit 1
fi
#Eg: ID_SERIAL --> /dev/disk/by-id/usb-sandisk....42343254343543
#i=0
echo 'searching partitions' >> "$lfile"
for partitionPath in $( find /dev/disk/by-id/ -name "*$ID_SERIAL*part*" )
do
echo "current partition = $partitionPath" >> "$lfile"
# part[i ]="$( readlink -f "$partition" )" # Eg Output: /dev/sdb1 , /dev/sdb2
part_c="$( readlink -f $partitionPath )"
mpoint="$( cat /etc/mtab | grep "^$part_c" | awk '{print $2}' )"
echo "partitionPath= $partitionPath, part = $part_c, mountpoint= $mpoint" >> "$lfile"
echo "Scaning --> $mpoint" >> "$lfile.2"
############################################
clamscan -r --bell "$mpoint"/* >> "$lfile.2"
#############################################
done
}
notify-send "USB SCAN ON INSERT" "Finished scanning with ClamAV"
main &
echo ______________________________________ >> "$lfile"
exit 0
I'm pretty new to the linux world, but while looking for a solution for a similar project I found THIS
Tip: An overview on the available icons can be found here. To send
desktop notification from a background script running as root (replace
X_user and X_userid with the user and userid running X respectively):
sudo -u X_user DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/X_userid/bus notify-send 'Hello world!' 'This is an example notification.'
Hope this will help others.
Depending on how you are running the script it may not have access to the display variable. Try running export DISPLAY=:0.0 prior to the command.
If you are running the script as a different user, ie root, then you may also need to run it as su - <logged in user> -c notify-send ... (I usually don't need to do this, but I remember having to at one point - but I cant recall which distro or version I was on at the time.)
I'm working on a script to automate the creation of a .gitconfig file.
This is my main script that calls a function which in turn execute another file.
dotfile.sh
COMMAND_NAME=$1
shift
ARG_NAME=$#
set +a
fail() {
echo "";
printf "\r[${RED}FAIL${RESET}] $1\n";
echo "";
exit 1;
}
set -a
sub_setup() {
info "This may overwrite existing files in your computer. Are you sure? (y/n)";
read -p "" -n 1;
echo "";
if [[ $REPLY =~ ^[Yy]$ ]]; then
for ARG in $ARG_NAME; do
local SCRIPT="~/dotfiles/setup/${ARG}.sh";
[ -f "$SCRIPT" ] && echo "Applying '$ARG'" && . "$SCRIPT" || fail "Unable to find script '$ARG'";
done;
fi;
}
case $COMMAND_NAME in
"" | "-h" | "--help")
sub_help;
;;
*)
CMD=${COMMAND_NAME/*-/}
sub_${CMD} $ARG_NAME 2> /dev/null;
if [ $? = 127 ]; then
fail "'$CMD' is not a known command or has errors.";
fi;
;;
esac;
git.sh
git_config() {
if [ ! -f "~/dotfiles/git/gitconfig_template" ]; then
fail "No gitconfig_template file found in ~/dotfiles/git/";
elif [ -f "~/dotfiles/.gitconfig" ]; then
fail ".gitconfig already exists. Delete the file and retry.";
else
echo "Setting up .gitconfig";
GIT_CREDENTIAL="cache"
[ "$(uname -s)" == "Darwin" ] && GIT_CREDENTIAL="osxkeychain";
user " - What is your GitHub author name?";
read -e GIT_AUTHORNAME;
user " - What is your GitHub author email?";
read -e GIT_AUTHOREMAIL;
user " - What is your GitHub username?";
read -e GIT_USERNAME;
if sed -e "s/AUTHORNAME/$GIT_AUTHORNAME/g" \
-e "s/AUTHOREMAIL/$GIT_AUTHOREMAIL/g" \
-e "s/USERNAME/$GIT_USERNAME/g" \
-e "s/GIT_CREDENTIAL_HELPER/$GIT_CREDENTIAL/g" \
"~/dotfiles/git/gitconfig_template" > "~/dotfiles/.gitconfig"; then
success ".gitconfig has been setup";
else
fail ".gitconfig has not been setup";
fi;
fi;
}
git_config
In the console
$ ./dotfile.sh --setup git
[ ?? ] This may overwrite existing files in your computer. Are you sure? (y/n)
y
Applying 'git'
Setting up .gitconfig
[ .. ] - What is your GitHub author name?
Then I cannot see what I'm typing...
At the bottom of dotfile.sh, I redirect any error that occurs during my function call to /dev/null. But I should normally see what I'm typing. If I remove 2> /dev/null from this line sub_${CMD} $ARG_NAME 2> /dev/null;, it works!! But I don't understand why.
I need this line to prevent my script to echo an error in case my command doesn't exists. I only want my own message.
e.g.
$ ./dotfile --blahblah
./dotfiles: line 153: sub_blahblah: command not found
[FAIL] 'blahblah' is not a known command or has errors
I really don't understand why the input in my sub script is redirected to /dev/null as I mentioned only stderr to be redirected to /dev/null.
Thanks
Do you need the -e option in your read statements?
I did a quick test in an interactive shell. The following command does not echo characters :
read -e TEST 2>/dev/null
The following does echo the characters
read TEST 2>/dev/null
Some weeks ago I found in this site a very useful bash script that downloads images from google image results (download images from google with command line)
Although the script is quite complicate for me, I did some simple modifications so as not to rename the results so as to keep the original names.
However, since the last week, the script stopped working... probably Google updated the code or something, and the regexes of the script don't parse the results any more. I don't know enough about google's codes, web programing or regexing to see what is wrong, although I did some educated guesses, but still didn't work.
My (unworking) tweaked script is this
#! /bin/bash
# function to create all dirs til file can be made
function mkdirs {
file="$1"
dir="/"
# convert to full path
if [ "${file##/*}" ]; then
file="${PWD}/${file}"
fi
# dir name of following dir
next="${file#/}"
# while not filename
while [ "${next//[^\/]/}" ]; do
# create dir if doesn't exist
[ -d "${dir}" ] || mkdir "${dir}"
dir="${dir}/${next%%/*}"
next="${next#*/}"
done
# last directory to make
[ -d "${dir}" ] || mkdir "${dir}"
}
# get optional 'o' flag, this will open the image after download
getopts 'o' option
[[ $option = 'o' ]] && shift
# parse arguments
count=${1}
shift
query="$#"
[ -z "$query" ] && exit 1 # insufficient arguments
# set user agent, customize this by visiting http://whatsmyuseragent.com/
useragent='Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:31.0) Gecko/20100101 Firefox/31.0'
# construct google link
link="www.google.cz/search?q=${query}\&tbm=isch"
# fetch link for download
imagelink=$(wget -e robots=off --user-agent "$useragent" -qO - "$link" | sed 's/</\n</g' | grep '<a href.*\(png\|jpg\|jpeg\)' | sed 's/.*imgurl=\([^&]*\)\&.*/\1/' | head -n $count | tail -n1)
imagelink="${imagelink%\%*}"
# get file extention (.png, .jpg, .jpeg)
ext=$(echo $imagelink | sed "s/.*\(\.[^\.]*\)$/\1/")
# set default save location and file name change this!!
dir="$PWD"
file="google image"
# get optional second argument, which defines the file name or dir
if [[ $# -eq 2 ]]; then
if [ -d "$2" ]; then
dir="$2"
else
file="${2}"
mkdirs "${dir}"
dir=""
fi
fi
# construct image link: add 'echo "${google_image}"'
# after this line for debug output
google_image="${dir}/${file}"
# construct name, append number if file exists
if [[ -e "${google_image}${ext}" ]] ; then
i=0
while [[ -e "${google_image}(${i})${ext}" ]] ; do
((i++))
done
google_image="${google_image}(${i})${ext}"
else
google_image="${google_image}${ext}"
fi
# get actual picture and store in google_image.$ext
wget --max-redirect 0 -q "${imagelink}"
# if 'o' flag supplied: open image
[[ $option = "o" ]] && gnome-open "${google_image}"
# successful execution, exit code 0
exit 0
one way to invetigate : provide -x option to bash so to have the trace of your script; that is change /bin/bash to /bin/bash -x in your script -or- simply invoke your script with
bash -x <yourscript>
You can also annotate your script with echo commands to track some variables.
We are deploying code to our application server environment, and part of that process is creating a number of cron jobs on the server. When code gets pushed, our deployment script creates the required cron jobs without a problem using the following:
CRON_FILE=$SCRIPT_DIR/cron.txt
if [[ ! -f "$CRON_FILE" ]]; then
printf "Cron template file missing!\n\n"
exit 1
fi
while read LINE || [[ -n "$LINE" ]]; do
printf "\n> Adding cron job \"$LINE\"\n"
crontab -l | { cat; echo "$LINE"; } | crontab -
done < $CRON_FILE
The issue is that after the initial deployment, additional deployments are creating duplicate cron jobs.
Any pointers on how to detect if a cron job already exists?
When you add your cron job, include a comment with a unique label. Later you can use that unique label to determine if the cron job exists or not, and also to "uninstall" the cron job.
I do this all the time. I have a reusable script for this:
#!/bin/sh
#
# Usage:
# 1. Put this script somewhere in your project
# 2. Edit "$0".crontab file, it should look like this,
# but without the # in front of the lines
#0 * * * * stuff_you_want_to_do
#15 */5 * * * stuff_you_want_to_do
#* * 1,2 * * and_so_on
# 3. To install the crontab, simply run the script
# 4. To remove the crontab, run ./crontab.sh --remove
#
cd $(dirname "$0")
test "$1" = --remove && mode=remove || mode=add
cron_unique_label="# $PWD"
crontab="$0".crontab
crontab_bak=$crontab.bak
test -f $crontab || cp $crontab.sample $crontab
crontab_exists() {
crontab -l 2>/dev/null | grep -x "$cron_unique_label" >/dev/null 2>/dev/null
}
# if crontab is executable
if type crontab >/dev/null 2>/dev/null; then
if test $mode = add; then
if ! crontab_exists; then
crontab -l > $crontab_bak
echo 'Appending to crontab:'
cat $crontab
crontab -l 2>/dev/null | { cat; echo; echo $cron_unique_label; cat $crontab; echo; } | crontab -
else
echo 'Crontab entry already exists, skipping ...'
echo
fi
echo "To remove previously added crontab entry, run: $0 --remove"
echo
elif test $mode = remove; then
if crontab_exists; then
echo Removing crontab entry ...
crontab -l 2>/dev/null | sed -e "\?^$cron_unique_label\$?,/^\$/ d" | crontab -
else
echo Crontab entry does not exist, nothing to do.
fi
fi
fi
Save the script as crontab.sh in your project directory, and create a crontab.sh.crontab with your cron job definitions, for example:
0 0 * * * echo hello world
0 0 * * * date
To install your cron jobs, simply run ./crontab.sh
The script is safe to run multiple times: it will detect if the unique label already exists and skip adding your cron jobs again
To uninstall the cron jobs, run ./crontab.sh --remove
I put this on GitHub too: https://github.com/janosgyerik/crontab-script
Explanation of sed -e "\?^$cron_unique_label\$?,/^\$/ d":
In its simplest form the expression is basically: sed -e '/start/,/end/ d'
It means: delete the content between the lines matching the start pattern and the end pattern, including the lines containing the patterns
The script quotes the sed command with double-quotes instead of single quotes, because it needs to expand the value of the $cron_unique_label shell variable
The start pattern \?^$cron_unique_label\$? uses a pair of ? instead of / to enclose the pattern, because $cron_unique_label contains /, which would cause problems
The starting ? must be escaped with a backslash, but to be honest I don't know why.
The ^ matches start of the line and $ end of the line, and the $ must be escaped, otherwise the shell would expand the value of the $? shell variable
The end pattern /^\$/ is relatively simple, it matches a start of line followed by end of line, in other words an empty line, and again the $ must be escaped
The d at the end is the sed command, to delete the matched lines, effectively removing it from the content of crontab -l, which we can pipe to crontab -
Weird, but very thorough answers. IMO overly complex.
Here's a decent one liner for anyone coming to this for a 2017 answer:
crontab -l | grep 'match-your-cronjob-search' || (crontab -l 2>/dev/null; echo "* * * * * /bin/cronjobCommandYouWant >> /dev/null 2>&1") | crontab -
Works great for us to not have dupe crons.
And here's the edited script from the original poster:
CRON_FILE=$SCRIPT_DIR/cron.txt
if [[ ! -f "$CRON_FILE" ]]; then
printf "Cron template file missing!\n\n"
exit 1
fi
while read LINE || [[ -n "$LINE" ]]; do
printf "\n> Adding cron job \"$LINE\"\n"
crontab -l | grep "$LINE" || (crontab -l 2>/dev/null; echo "$LINE") | crontab -
done < $CRON_FILE
Your script janos is awesome, works perfectly and was exactly what i was looking for with one little glitch.
I couldnt manage multiple xxx.crontab templates.
Your script worked fine and i added it to my bootstrapping routines with a little modification so i can pass a first parameter $1 of the xx.crontab filename and second parameter $2 can be the removal.
I have parent shell scripts which then conditional decide, which, all or combination of crontab files i want to add/remove.
Here the script with my modifications included:
#!/bin/sh
#
# Usage:
# 1. Put this script somewhere in your project
# 2. Edit "$1".crontab file, it should look like this,
# but without the # in front of the lines
#0 * * * * stuff_you_want_to_do
#15 */5 * * * stuff_you_want_to_do
#* * 1,2 * * and_so_on
# 3. To install the crontab, run ./crontab.sh <nameOfCronTabfile>
# 4. To remove the crontab, run ./crontab.sh <nameOfCronTabfile> --remove
cd $(dirname "$0")
test "$2" = --remove && mode=remove || mode=add
cron_unique_label="# cmID:$PWD|$1#"
crontab="$1".crontab
crontab_bak=$crontab.bak
test -f $crontab || cp $crontab.sample $crontab
crontab_exists() {
crontab -l 2>/dev/null | grep -x "$cron_unique_label" >/dev/null 2>/dev/null
}
# if crontab is executable
if type crontab >/dev/null 2>/dev/null; then
if test $mode = add; then
if ! crontab_exists; then
crontab -l > $crontab_bak
echo 'Appending to crontab:'
echo '-----------------------------------------------'
cat $crontab
crontab -l 2>/dev/null | { cat; echo; echo $cron_unique_label; cat $crontab; echo "# cm #"; } | crontab -
else
echo 'Crontab entry already exists, skipping ...'
echo
fi
echo '-----------------------------------------------'
echo "To remove previously added crontab entry, run: $0 $1 --remove"
echo
elif test $mode = remove; then
if crontab_exists; then
echo 'Removing crontab entry ...'
crontab -l 2>/dev/null | sed -e "\?^$cron_unique_label\$?,/^# cm #\$/ d" | crontab -
else
echo 'Crontab entry does not exist, nothing to do.'
fi
fi
fi
UPDATE:
Sry, didnt noticed the weak empty line pattern for removing a crontab. Simply would delete everything after the found crontab id, including manually added crontabs.
Changed the empty line end pattern to a little end tag.
So it will add crontabs with:
crontab -l 2>/dev/null | { cat; echo; echo $cron_unique_label; cat $crontab; echo "# cm #"; } | crontab -
.. and removing exactly only this cron with:
crontab -l 2>/dev/null | sed -e "\?^$cron_unique_label\$?,/^# cm #\$/ d" | crontab -
We can also do it in code:
first in bash, check the manual: man 2 open:
int fd = open('/tmp/1.txt', O_CREAT|O_EXCL)
if (fd === -1) {
print "job exist"
exit(1)
}
//unlink()
// your code
Js version:
const fs = require('fs')
try {
const fd = fs.openSync('/tmp/1.txt', 'wx')
} catch(err) {
console.log('job exist')
process.exit(0)
}
fs.unlinkSync('/tmp/1.txt')
fs.appendFileSync(fd, 'pid', 'utf8');