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.
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'm trying to create a script, where multiple user inputs are being accepted. When I call the script, and provide multiple inputs the script won't execute when multiple inputs are provided. What am I doing wrong here.
#! /bin/bash
server_list=()
echo "Enter server name: "
readarray -t servername
declare -p servername
sudo showsudolocal $servername | tr -d '$' | sed -e '/^$/d' | tee output.txt
sed -i 1,8d output.txt
mapfile -t myArray < output.txt
count=${#myArray[#]}
for (( i=1; i<$count; ))
#for i in `seq 1 $count`
do
str="${myArray[$i]}"
echo "str is $str"
IFS=',' read -r -a array <<< "$str"
i=$((i+2))
username="${array[0]}"
groupname="${array[1]}"
echo "Username is $username"
if [[ -z "${array[0]}" ]] || [[ "${array[0]}" == *'*'* ]]
then
echo "group"
sudo docentcmd $servername centclicmd adquery group $groupname
cat /etc/group | grep $groupname
else
echo "User"
sudo docentcmd $servername centclicmd adquery user $username
cat /etc/passwd | grep $username
fi
done
I am on debian 9.
I have a problem to check the password of a linux user in my scripts. I realized that the different linux tools for creating and modifying a user password gave results of different pattern in /etc/shadow
To create a user
pwLinux="abcdef1234"
userLinux="toto02"
pwCrypt=$(perl -e 'print crypt($ARGV[0], "zzz")' $pwLinux)
useradd -m -G adm,dip,plugdev,www-data,sudo -p $pwCrypt $userLinux
I have in /etc/shadow
toto02:zzDxrNjXuUs3U:17469:0:99999:7:::
In another script I want check the password input by the user with
USERNAME="toto02"
PASSWD="abcdef1234"
ORIGPASS=`grep -w "$USERNAME" /etc/shadow | cut -d: -f2`
ORIGPASS=`echo $ORIGPASS | cut -d"$" -f2`
GENPASS=$(perl -e 'print crypt($ARGV[0], "zzz")' $PASSWD)
if [ "$GENPASS" == "$ORIGPASS" ]; then
echo "Valid Password"
exit 0
else
echo "Invalid Password"
exit 1
fi
it's ok
The trouble starts here: if I want to change passwords in a script I use
# username "toto02", newPwd "aabbcc"
echo "${username}:${newPwd}" | chpasswd
I can not use passwd because everything has to be done without interactivity.
I have in /etc/shadow
toto02:$6$rLklwx9K$Brv4lvNjR.S7f8i.Lmt8.iv8pgcbKhwDgINzhT1XwCBbD7XkB98lCtwUK3/4hdylkganoLuh/eIc38PtMArgZ/:17469:0:99999:7:::
If i want to check this password i must use a different script.
First problem how to have the same pattern of password in both cases?
i use:
#!/bin/bash
USERNAME="toto02"
PASSWD="aabbcc"
ORIGPASS=`grep -w "$USERNAME" /etc/shadow | cut -d: -f2`
export ALGO=`echo $ORIGPASS | cut -d"$" -f2`
export SALT=`echo $ORIGPASS | cut -d"$" -f3`
echo "algo: -$ALGO-"
echo "salt: -$SALT-"
echo "pwd entré: -$PASSWD-"
echo "shadow: -$ORIGPASS-"
GENPASS="$(perl -e 'print crypt("$ENV{PSWD}","\$$ENV{ALGO}\$$ENV{SALT}\$")')"
echo "pwd généré: -$GENPASS-"
if [ "$GENPASS" == "$ORIGPASS" ]; then
echo "Valid Password"
exit 0
else
echo "Invalid Password"
exit 1
fi
Which give:
algo: -6-
salt: -rLklwx9K-
pwd entré: -aabbcc-
shadow: -$6$rLklwx9K$Brv4lvNjR.S7f8i.Lmt8.iv8pgcbKhwDgINzhT1XwCBbD7XkB98lCtwUK3/4hdylkganoLuh/eIc38PtMArgZ/-
pwd généré: -$6$rLklwx9K$AIX1bUMAK9bwdd2g3ST5VtXTvHlHXHxnh4Xj.fLdxjaEkAAvHeeN5islid0wtmZN5u1zWQBup./IP8IH9i6W7/-
Invalid Password
The generated chain is different! why?
How to cure it ?
Thank you
Replace PSWD with PASSWD and replace PASSWD="aabbcc" with export PASSWD="aabbcc".
YES is good now
it's been hours that I'm on and I could not see anything!
#!/bin/bash
USERNAME=$1 # "toto02"
export PASSWD=$2 # "aabbcc"
ORIGPASS=`grep -w "$USERNAME" /etc/shadow | cut -d: -f2`
export ALGO=`echo $ORIGPASS | cut -d"$" -f2`
export SALT=`echo $ORIGPASS | cut -d"$" -f3`
echo "algo: -$ALGO-"
echo "salt: -$SALT-"
echo "pw entré: -$PASSWD-"
echo "shadow: -$ORIGPASS-"
GENPASS="$(perl -e 'print crypt("$ENV{PASSWD}","\$$ENV{ALGO}\$$ENV{SALT}\$")')"
echo "pass génére: -$GENPASS-"
if [ "$GENPASS" == "$ORIGPASS" ]; then
echo "Valid Password"
exit 0
else
echo "Invalid Password"
exit 1
fi
algo: -6-
salt: -rYc.lGtG-
pw entré: -aabbcc-
shadow: -$6$rYc.lGtG$wMHAM.nXHk1J5sDRmcHeBLW1sRQA/xQcjJSZxkls4BratyWf.KoQST14pPjNWDiUKwfegC96Lhjgjbj4YbZoc.-
pass génére: -$6$rYc.lGtG$wMHAM.nXHk1J5sDRmcHeBLW1sRQA/xQcjJSZxkls4BratyWf.KoQST14pPjNWDiUKwfegC96Lhjgjbj4YbZoc.-
Valid Password
Thank you very much, but is there a way to have the same type of password with useradd and chpasswd
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
I'm making a bash script which should create an ftp user.
ftpasswd --passwd --file=/usr/local/etc/ftpd/passwd --name=$USER --uid=[xxx]
--home=/media/part1/ftp/users/$USER --shell=/bin/false
The only supplied argument to script is user name. But ftpasswd also requires uid. How do I get this number? Is there an easy way to scan passwd file and get the max number, increment it and use it? Maybe it's possible to obtain that number from the system?
Instead of reading /etc/passwd, you can also do it in a more nsswitch-friendly way:
getent passwd
Also don't forget that there isn't any guarantee that this sequence of UIDs will be already sorted.
To get UID given an user name "myuser":
cat /etc/passwd | grep myuser | cut -d":" -f3
To get the greatest UID in passwd file:
cat /etc/passwd | cut -d":" -f3 | sort -n | tail -1
To get a user's UID:
cat /etc/passwd | grep "^$usernamevariable:" | cut -d":" -f3
To add a new user to the system the best option is to use useradd, or adduser if you need a fine-grained control.
If you really need just to find the smallest free UID, here's a script that finds the smallest free UID value greater than 999 (UIDs 1-999 are usually reserved to system users):
#!/bin/bash
# return 1 if the Uid is already used, else 0
function usedUid()
{
if [ -z "$1" ]
then
return
fi
for i in ${lines[#]} ; do
if [ $i == $1 ]
then
return 1
fi
done
return 0
}
i=0
# load all the UIDs from /etc/passwd
lines=( $( cat /etc/passwd | cut -d: -f3 | sort -n ) )
testuid=999
x=1
# search for a free uid greater than 999 (default behaviour of adduser)
while [ $x -eq 1 ] ; do
testuid=$(( $testuid + 1))
usedUid $testuid
x=$?
done
# print the just found free uid
echo $testuid
I changed cat /etc/passwd to getent passwd for Giuseppe's answer.
#!/bin/bash
# From Stack Over Flow
# http://stackoverflow.com/questions/3649760/how-to-get-unique-uid
# return 1 if the Uid is already used, else 0
function usedUid()
{
if [ -z "$1" ]
then
return
fi
for i in ${lines[#]} ; do
if [ $i == $1 ]
then
return 1
fi
done
return 0
}
i=0
# load all the UIDs from /etc/passwd
lines=( $( getent passwd | cut -d: -f3 | sort -n ) )
testuid=999
x=1
# search for a free uid greater than 999 (default behaviour of adduser)
while [ $x -eq 1 ] ; do
testuid=$(( $testuid + 1))
usedUid $testuid
x=$?
done
# print the just found free uid
echo $testuid
This is a much shorter approach:
#!/bin/bash
uids=$( cat /etc/passwd | cut -d: -f3 | sort -n )
uid=999
while true; do
if ! echo $uids | grep -F -q -w "$uid"; then
break;
fi
uid=$(( $uid + 1))
done
echo $uid
since this is bash things could get simpler
#!/bin/bash
get_available_uid_basic(){
local uid_free=1000
local uids_in_use=( $(cut -d: -f3 < /etc/passwd) )
while [[ " ${uids_in_use[#]} " == *" $uid_free "* ]]; do
(( uid_free++ ))
done
echo $uid_free
}
uid=$(get_available_uid_basic)
echo $uid
Explanation:
uids_in_use is an array to get rid of new-line characters
there is no "| sort" and it's useless in other answers too
${uids_in_use[#]} is uids_in_use array exploded with spaces as separators
there are spaces before and after first and last array entry, so each entry is separated by spaces on each side
bash's [[ ]] accepts glob character after '=='
System/User uid and first/last available
useradd/adduser has --system argument, this creates user with uid between 100-999
also, useradd does look for available uid starting at 999 going downwards.
In my case I needed both of these behaviors, this is a function which accepts "system" and "reverse" arguments
#!/bin/bash
get_available_uid(){
local system_range
[[ $* == *system* ]] && system_range=TRUE
local reverse
[[ $* == *reverse* ]] && reverse=TRUE
local step
local uid_free
if [ -n "$system_range" ]; then
if [ -n "$reverse" ]; then
uid_free=999
step=-1
else
uid_free=100
step=1
fi
else
if [ -n "$reverse" ]; then
uid_free=9999
step=-1
else
uid_free=1000
step=1
fi
fi
local uids_in_use=( $(cut -d: -f3 < /etc/passwd) )
while [[ " ${uids_in_use[#]} " == *" $uid_free "* ]]; do
(( uid_free+=step ))
done
if [ -n "$system_range" ]; then
if (( uid_free < 100 )) || (( uid_free > 999 )); then
echo "No more available uids in range" >&2
return 1
fi
else
if (( uid_free < 1000 )); then
echo "No more available uids in range" >&2
return 1
fi
fi
echo $uid_free
return 0
}
uid=$(get_available_uid)
echo "first available user uid: $uid"
uid=$(get_available_uid system)
echo "first available system uid: $uid"
uid=$(get_available_uid reverse)
echo "last available user uid: $uid"
uid=$(get_available_uid system reverse)
echo "last available system uid: $uid"