I want to add linux users then i want to restrict them as hard as possible. (noshell etc) from a file called users.
This is my code but not working:
while read line
do
input = echo ($input | tr ":" "\n")
#!/bin/bash
# Script to add a user to Linux system
if [ $(id -u) -eq 0 ]; then
if [ $? -eq 0 ]; then
echo "$username exists!"
exit 1
else
pass=$(perl -e 'print crypt($ARGV[0], "password")' $input[1)
useradd -m -p $input[1] $input[0]
[ $? -eq 0 ] && echo "User has been added to system!" || echo "Failed to add a user!"
fi
else
echo "Only root may add a user to the system"
exit 2
fi
done < /var/www/users
Then i want to restrict their accounts with noshell. (but i know how can i do. But i cant separate the input from the file correctly :/)
input(users):
john:lol
rambo:sanyi
cula:kari
Thank you very much!
I think, following script will do:
#!/bin/bash
USERS=`cat /etc/passwd | cut -d: -f1`
if [ `id -u` -ne 0 ]
then
echo "Login as Root"
else
while read line
do
USER=`echo $line | cut -d ":" -f1`
PASS=`echo $line | cut -d ":" -f2`
echo $USERS | grep "${USER}" > /dev/null
if [ $? -eq 0 ]
then
echo "Username ${USER} Exists!"
else
password=`perl -e 'print crypt("${PASS}", "salt")', "\n"`
useradd -p "${password}" ${USER}
echo "User ${USER} created!"
fi
i+=1
done < /var/www/users
fi
Related
I am now trying to create users in Ubuntu from a text file and it looks like this:
student1
student2
student3
student4
student5
However, I keep getting invalid user name error. For instance
'seradd: invalid user name 'student5
Here is my code. The first argument is input file and the second input is output file. Can anyone help?
#!/bin/bash
if test ${#} -lt 1
then
echo "Please provide the input file"
exit 1
else
cat ${1} | while read user
do
randompw=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1)
useradd -m -s /bin/bash ${user}
echo ${newuser}:${randompw} | chpasswd
if test $# -lt 2
then
echo ${newuser}:${randompw} >> pwlist.txt
else
echo ${newuser}:${randompw} >> ${2}
fi
if id -u ${user}
then
echo "User account ${user} created successfully"
else
echo "User account ${user} created unsuccessfully"
fi
done
fi
The variable newuser is not defined. I think you meant $user instead.
Suggestion:
Enclose variable references and computations within double quotes. I fixed that.
#!/bin/bash
if test ${#} -lt 1
then
echo "Please provide the input file"
exit 1
else
cat "${1}" | while read user
do
randompw="$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1)"
useradd -m -s /bin/bash "${user}"
echo "${user}:${randompw}" | chpasswd
if test $# -lt 2
then
echo "${user}:${randompw}" >> pwlist.txt
else
echo "${user}:${randompw}" >> ${2}
fi
if id -u "${user}"
then
echo "User account ${user} created successfully"
else
echo "User account ${user} created unsuccessfully"
fi
done
fi
I want to check three conditions before I run the command: If string (username) match to regexp, if user exists and if user belongs to certain group:
PASSWORD=`/usr/bin/pwgen -sync -1 15`
CHPASSWD=/usr/sbin/chpasswd
FILE=/tmp/password
USER_GROUP=somegroup
while true
do
echo -ne "username: "; read USER_NAME
if [[ "$USER_NAME" =~ ^[a-z_][a-z0-9_]*[$]?$ ]] &&
[[ `getent group $USER_GROUP | grep -o $USER_NAME` -eq 0 ]] &&
[[ `getent passwd $USER_NAME | cut -d ':' -f -1` -eq 0 ]]
then
break
else
echo "error"
fi
done
echo $USER_NAME:$PASSWORD > $FILE
sudo $CHPASSWD < $FILE
rm -f $FILE
The above code works partially only. It checks for regexp and group but it is trying to change password for even if user doesn't exist.
The right solution is:
while true
do
echo -ne "username: "; read USER_NAME
if [[ "$USER_NAME" =~ ^[a-z_][a-z0-9_]*[$]?$ ]]
then
if [[ `getent group $USER_GROUP | grep -w -c "$USER_NAME"` -eq 1 ]]
then
break
else
echo "User not in the right group"
fi
else
echo "Invalid characters"
fi
done
I am trying to output which accounts have been successfully created from a text file and which haven't. I would also like to output the number of successfully created accounts. I currently the get the following error: grep: 3: No such file or directory. The script and text file and saved in the same folder. I have use the following commands in my script.
file=users.txt
verify =grep "verify" $file |cut -f2 -d:`
cat /etc/passwd | grep $verify
echo -e "\nYou have Currently"
cat /etc/passwd | grep $verify |wc -l;
echo "users added from your Text File"
Edit:
#!/bin/bash
ROOT_UID=0 #The root user has a UID of 0
if [ "$UID" -ne "$ROOT_UID" ]; then
echo "**** You must be the root user to run this script!****"
exit
fi
clear
echo
echo "######################################################"
echo "##### Batch script to automate creation of users #####"
echo -e "######################################################\n"
while true;
do
file=notvalid
while [ $file == "notvalid" ]
do
#echo "repeat $repeat"
#echo -e "\n"
echo -n "Please enter import filename:"
read filename
echo -e "\r"
exists=0
if [ -e $filename ]; then
file=valid
while IFS=":" read firstname lastname userid password group
do
egrep -i "^$userid:" /etc/passwd &>/dev/null
if [ $? -eq 0 ]; then
exists=$((exists+1))
#echo -e "${firstname} ${lastname} already exists on the system"
#grep ${userid} /etc/passwd
aname=$( getent passwd "$userid" | cut -d: -f3)
echo "Account Exists: $aname"
euserid=$( getent passwd "$userid" | cut -d: -f1)
echo "User ID: $userid"
homedir=$( getent passwd "$userid" | cut -d: -f6)
echo "Home Directory: $homedir"
usershell=$( getent passwd "$userid" | cut -d: -f7)
echo "User Shell: $usershell"
g=$( id -Gn "$userid")
echo "Groups: $g"
echo -e "\r"
else
egrep -i "^$group:" /etc/group &>/dev/null
if [ $? -eq 1 ]; then
/usr/sbin/addgroup ${group} &>/dev/null
fi
useradd -d /home/"${userid}" -m -s /bin/bash -c \
"${firstname}${lastname}" -g "${group}" "${userid}"
echo "Creating Account: ${firstname} ${lastname}"
nuserid=$( getent passwd "$userid" | cut -d: -f1)
echo "Creating User ID: ${nuserid}"
{ echo ${password}; echo ${password}; } | sudo passwd ${userid} > /dev/null 2>&1
echo "Creating Password: ${password}"
echo "Creating Home Directory: /home/${userid}"
echo "Creating User Shell: /bin/bash"
echo -e "Assigning Group: ${group}\n"
fi
done < $filename
else
echo -e "##### CANNOT FIND OR LOCATE FILE #####"
fi
verify=`grep "verify" /home/pi/$filename | cut -f3 -d:`
echo "$verify"
count=0
for id in $verify
do grep -wo ^$id /etc/passwd && count=$((count+1))
done
echo $count users added from your text file
echo these are not added:
for id in $verify
do grep -wq ^$id /etc/passwd || echo $id
done
while true
do
echo -n "Create additional accounts [y/n]: "
read opt
if [[ $opt == "n" || $opt == "y" ]];then
break
else
echo "Invalid Input"
fi
done
if [ $opt = "n" ]; then
clear
break
else
clear
fi
done
You were almost there.
The main issue with your approach is that you try to search for multiple accounts at once with grep. The variable verify has multiple userids so you need to process it one by one.
file=users.txt
verify=`grep "verify" $file | cut -f2 -d:`
count=0
for id in $verify
do grep -wo ^$id /etc/passwd && count=$((count+1))
done
echo $count users added from your text file
echo these are not added:
for id in $verify
do grep -wq ^$id /etc/passwd || echo $id
done
The for loop will take each element in your verify variable into id and search with grep (-w matches only whole words, not fragments, ^ matches the beginning of line and -o outputs only the matching word not the whole line).
We count the number of matches in the count variable. Alternative approach to run the for loop twice and pipe the second one to wc -l as you did.
&& operator means it will increase count if the previous command found a match (the return code of grep was 0).
The next loop will not print matching ids (-q), and will echo id if grep did not found a match (the return code was not 0). This is achieved with the || operator.
One last note on iteration of a list: if the members can contain spaces (unlike userids), you should use ${verify[#]} (this is a bash-ism) instead of $verify .
And forget this: cat /etc/passwd | grep pattern, use grep pattern /etc/passwd instead.
I wrote a shell script for detecting whether a package is installed or not. My script should write its name and status if it's installed. I can't figure out any problem with my code but when I run it, it doesn't execute the commands under if [ $? == 0 ] condition.
#!/bin/bash
if [ "$1" == "" ]; then
echo "Please hold the line."
else
dpkg -s $# &> /dev/null
fi
if [ $? == 1 ]; then
echo -e "Package \033[0;31mNOT\033[0m found." >&2
else
if [ $? == 0 ]; then
for i in $#; do
dpkg -s $i | grep Package
dpkg -s $i | grep Status
done
fi
fi
But the most weird thing to me is that it works if I add an echo after if statement. Looks like that:
#!/bin/bash
if [ "$1" == "" ]; then
echo "Please hold the line."
else
dpkg -s $# &> /dev/null
fi
if [ $? == 1 ]; then
echo -e "Package \033[0;31mNOT\033[0m found." >&2
else
echo hi
if [ $? == 0 ]; then
for i in $#; do
dpkg -s $i | grep Package
dpkg -s $i | grep Status
done
fi
fi
So if I add an echo -n to right position in my code it will work as I want. But I just want to know what is wrong with first one?
I think in general you could be more deliberate about your return code handling. You are making assumptions about what $? is referring to that may not be valid depending on your program flow, and regardless, make the program harder to read and understand.
#!/bin/bash
dpkg -s $# &> /dev/null
installed=$?
if [ $installed -eq 0 ]; then
for i in $#; do
dpkg -s $i | grep Package
dpkg -s $i | grep Status
done
else
echo -e "Package \033[0;31mNOT\033[0m found." >&2
fi
$? is the return status of the last executed command. 0 is successful, 1 or anything else is an error. Note:
dpkg -s python &> /dev/null # returns 0 (OK, true)
# $? equals 0 now
[ #? == 1 ] # false # returns 1 (error)
# $? equals 1 now
[ #? == 0 ] # false # returns 1 (error)
When you put echo, it works:
dpkg -s python &> /dev/null # returns 0 (OK, true)
# $? equals 0 now
[ #? == 1 ] # false # returns 1 (error)
# $? equals 1 now
echo hi # returns 0 (OK)
# $? equals 0 now
[ #? == 0 ] # true # returns 0 (OK)
You could save $? to a variable, but you don't really need the if inside the else since you already checked if #? == 1 so just put your code inside else:
#!/bin/bash
if [ "$1" == "" ]; then
echo "Please hold the line."
else
dpkg -s $# &> /dev/null
fi
if [ $? == 1 ]; then
echo -e "Package \033[0;31mNOT\033[0m found." >&2
else
for i in $#; do
dpkg -s $i | grep Package
dpkg -s $i | grep Status
done
fi
If you are worried of other possible return statuses of $? (greater than one). You could rewrite your script to
#!/bin/bash
if [ "$1" == "" ]; then
echo "Please hold the line."
else
dpkg -s $# &> /dev/null
fi
if [ $? == 0 ]; then
for i in $#; do
dpkg -s $i | grep Package
dpkg -s $i | grep Status
done
else
echo -e "Package \033[0;31mNOT\033[0m found." >&2
fi
Below is the assignment for the bash shell script I'm writing. I'm having a
problem with -u information being output even though I am using the -f option.
This class is a beginner class, so please bear with me. Would be grateful to
have some input on my code. Thanks for taking the time to check this out if you
do.
Here is the sample output:
[***#***]$ chk3 -f share
share is a directory and it is readable | writable | executable | abecker is
currently logged in their home directory is /students/abecker
Here is the usage
chk -f filepath
If filepath exists, output in readable sentences
if it is a symbolic link, say so. You do not have to continue and report the
permissions.
if it doesn't exist, say so. Don't continue to report the permissions
report what it is: file, directory, or something else, and continue to
report the permissions:
report what combination of read, write and execute access rights your
program has for the data. Note that this is dependent on who runs your
program. Do not attempt to do this by looking at the permissions as output
by ls -l. You must use the test operators to do this.
If filepath does not exist (and is not a symbolic link), your program should
report this instead in an informative error message. In this case, you
should exit with an error.
chk -u user
If the user exists on the system, report
the path to the user's home directory
if the user is currently logged in, say so. Otherwise, report when they last
logged in. (Take some care so that this is generated reliably and quickly.)
If the user doesn't exist, report this in an informative error message, and
exit with an error.
Here is my code
#!/bin/bash
if [ $# -gt 2 ]
then
echo "only 2 aruments can be used"
exit 1
fi
if [ "$1" != '-f' -a "$1" != '-u' ]
then
echo "first argument must be -f or -u"
exit 1
fi
if [ "$1" = '-f' -a $# -ne 2 ]
then
echo 'Usage: chk -f [FILEPATH]'
exit 1
fi
if [ "$1" = '-f' ]
then
FILEPATH=$2
fi
if [ -L "$FILEPATH" ]
then
echo "$FILEPATH is a symbolic link"
exit 0
elif [ -d "$FILEPATH" ]
then
echo -e "$(basename "$FILEPATH") is a directory and it is \c"
elif [ -f "$FILEPATH" ]
then
echo -e "$(basename "$FILEPATH") is a file and it is \c"
else
echo "I cannot determine what $(basename "$FILEPATH") is"
exit 1
fi
if [ -r "$FILEPATH" ]
then
echo -e "readable | \c"
fi
if [ -w "$FILEPATH" ]
then
echo -e "writable | \c"
fi
if [ -x "$FILEPATH" ]
then
echo -e "executable | \c"
fi
if [ "$1" = '-u' -a $# -eq 1 ]
then
USER=$LOGNAME
elif [ "$1" = '-u' -a $# -eq 2 ]
then
USER=$2
fi
USERINFO=$(grep "^$USER:" /etc/passwd)
if ! grep "^$USER:" /etc/passwd > /dev/null
then
echo "$USER cannot be found on this system"
exit 1
fi
if ! who | grep "^$USER " > /dev/null
then
echo "$USER is not currently logged on and last logged on"
echo "$(last -1 "$USER")"
exit 0
else
echo "$USER is currently logged in their home directory is"
echo "$(echo "$USERINFO" | awk -F":" '{print $6}')"
fi
You're not putting the processing of different options into different blocks; the code simply passes through everything for all options.
e.g. for the -f option, you have:
if [ "$1" = '-f' ]
then
FILEPATH=$2
fi
and then process all the options for filepath, without putting them into the if statement, so if you pass in either -f or -u, it always passes into the code:
if [ -L "$FILEPATH" ]
then
echo "$FILEPATH is a symbolic link"
exit 0
elif
If you don't want to break your program into functions, what you want to do is put all the code relating to processing the -f option into the same if-statement, somewhat like:
if [ "$1" = '-f' ]
then
FILEPATH=$2
if [ -L "$FILEPATH" ]
then
echo "$FILEPATH is a symbolic link"
exit 0
elif [ -d "$FILEPATH" ]
then
echo -e "$(basename "$FILEPATH") is a directory and it is \c"
elif [ -f "$FILEPATH" ]
then
echo -e "$(basename "$FILEPATH") is a file and it is \c"
else
echo "I cannot determine what $(basename "$FILEPATH") is"
exit 1
fi
if [ -r "$FILEPATH" ]
then
echo -e "readable | \c"
fi
if [ -w "$FILEPATH" ]
then
echo -e "writable | \c"
fi
if [ -x "$FILEPATH" ]
then
echo -e "executable | \c"
fi
fi # if [ "$1" = '-f' ]
Similarly for the -u option, you need to break it into multiple statements and then process all the options for the statement:
if [ "$1" = 'u' ]
then
if [ $# -eq 1 ]
then
USER=$LOGNAME
elif [ $# -eq 2 ]
then
USER=$2
fi
USERINFO=$(grep "^$USER:" /etc/passwd)
if ! grep "^$USER:" /etc/passwd > /dev/null
then
echo "$USER cannot be found on this system"
exit 1
fi
if ! who | grep "^$USER " > /dev/null
then
echo "$USER is not currently logged on and last logged on"
echo "$(last -1 "$USER")"
exit 0
else
echo "$USER is currently logged in their home directory is"
echo "$(echo "$USERINFO" | awk -F":" '{print $6}')"
fi
fi # if [ "$1" = '-u' ]
I would, however recommend putting the code that acts on the options into shell functions, which makes it much easier to read the code; e.g.
filepath() {
FILEPATH="$1"
if [ -L "$FILEPATH" ]
then
echo "$FILEPATH is a symbolic link"
exit 0
elif [ -d "$FILEPATH" ]
then
echo -e "$(basename "$FILEPATH") is a directory and it is \c"
elif [ -f "$FILEPATH" ]
then
echo -e "$(basename "$FILEPATH") is a file and it is \c"
else
echo "I cannot determine what $(basename "$FILEPATH") is"
exit 1
fi
if [ -r "$FILEPATH" ]
then
echo -e "readable | \c"
fi
if [ -w "$FILEPATH" ]
then
echo -e "writable | \c"
fi
if [ -x "$FILEPATH" ]
then
echo -e "executable | \c"
fi
}
And then for the processing code:
if [ "$1" = '-f' ]
then
filepath "$2"
fi
and something similar for the -u option.