How to get all the users from /etc/passwd which doesn't have a home directory - linux

I am trying to get all users whose home directories are mentioned in /etc/passwd but are not present in /home.
The below code gives me all the home directories which are not present in /home but are present in /etc/passwd.
cut -d":" -f6 /etc/passwd | grep home | sort |
while read dir; do [ -e "$dir" ] || echo Missing $dir; done
How do I get the list of corresponding users from the first column and create the corresponding /home directory using mkhomedir_helper(user) one by one from the list?

Other implementation of Barmar's solution:
getent passwd | sort -t: -k6 | while IFS=: read -r u _ _ _ _ d _
do
if [[ "$d" =~ ^/home/ ]] && ! [[ -d "$d" ]]
then printf 'Directory %q missing for user: %q\n' "$d" "$u"
fi
done
Using getent allow to pull the same data whenever it is a file or an NIS (Network Information Service).
[[ "$d" =~ ^/home/ ]] ensure the home directory starts with /home by matching it against Extended Regular Expression. ^/home/

You have to keep the username in the data that you read. You don't need to use cut, read can split the input into fields and assign them to variables.
grep /home/ /etc/passwd | sort -t: -k6 | while IFS=: read -r username _ _ _ _ dir _
do
if ! [ -d "$dir" ]
then
echo "Username $username missing $dir"
mkhomedir_helper "$username"
fi
done

Related

Bash Script To Remove Users From Wordlist

I wrote the following script to remove users from a wordlist. The wordlist has 3 or 4 fields which are First Name, Middle Name, Last Name, and User ID. I am using awk to create a username that comprises of the user's firstname initial, lastname and last two digits of their ID. Then using the command userdel with flag r to remove users with their home directories as well.
However when I run the script it gives me an error saying the following:
Usage: userdel [options] LOGIN
Options:
-f, --force force some actions that would fail otherwise
e.g. removal of user still logged in
or files, even if not owned by the user
-h, --help display this help message and exit
-r, --remove remove home directory and mail spool
-R, --root CHROOT_DIR directory to chroot into
-Z, --selinux-user remove any SELinux user mapping for the user
The script:
#! /bin/bash
# Removing users using positional parameters
getusername(){
line=${1}
len=`echo ${line}|awk '{ FS = " " } ; { print NF}'`
if [[ ${len} -eq 3 ]]
then
initial=`echo ${line}| awk {'print $1'} |cut -c1`
lastname=`echo ${line} | awk {'print $2'}`
id=`echo ${line}| awk {'print $3'}|grep -o '..$'`
username=`echo ${initial}${lastname}${id} |tr '[:upper:]' '[:lower:]'`
elif [[ ${len} -eq 4 ]]
then
initial=`echo ${line} | awk {'print $1'} |cut -c1`
lastname=`echo ${line} | awk {'print $3'}`
id=`echo ${line}| awk {'print $4'}|grep -o '..$'`
username=`echo ${initial}${lastname}${id} |tr '[:upper:]' '[:lower:]'`
else
echo "Line ${line} is not expected as it should be considered for creating Username and Password"
fi
}
sudo userdel -r $getusername
How to invoke userdel?
userdel -r username
This deletes the account of user username, and removes that user's home directory and associated mail files.
For that, you need to use a variable instead of to invoke a function.
Otherwise userdel will complain, like it is already doing or like just typing userdel.

Linux - List users which have specific directory

I am trying to create a script which will list the name of the user, only if that specific user has a specific and available directory in his folder.
#!/bin/bash
for i in `cat /etc/passwd | cut -d : -f5\,6 | cut -d : -f2`
do
cd $i
if [ -d public_html ]
then
echo `cat /etc/passwd | cut -d : -f5,6 | cut -d : -f1`
fi
done
First, I get a list of all the user names that have home folders.
Then, for each user, I enter in his directory
If in his directory, public_html directory is found, echo the user.
When I run this in the terminal, all the users are listed:
cat /etc/passwd | cut -d : -f5,6 | cut -d : -f1
However, I need to somehow get the user i from that whole list.
Can anybody be so kind to explain what I´m doing wrong, and what to look out for?
You're getting the wrong result because you're checking for a file (with -f). Try using -d.
Using cat and cut is not bash either and can easily be replaced with script in most cases.
I'd do something like this:
while IFS=: read -r user pass uid gid desc homedir shell; do [ -d "$homedir"/public_html ] && echo "$user"; done < /etc/passwd
We set the field separator (IFS) to : (since that's what /etc/passwd uses), we read the file in and set the variables we want to use.
Then for each line we do the test and (&&) if the test is successful we echo the result.
The quotes are not really necessary since we know the formatting of the file but good practice.
If users' home directories are set up in the standard way:
cd /home
for pubdir in */public_html/ ; do
echo "${pubdir%%/*}"
done
I did it ghetto style...
#!/bin/bash
counter=0
for i in `cat /etc/passwd | cut -d : -f6`
do
if [ -r $i ]
then
cd $i
if [ -d public_html ]
then
counter2=2
for j in `cat /etc/passwd | cut -d : -f5`
do
counter2=$(($counter2 + 1))
if [ $counter -eq $counter2 ]
then
echo $j
fi
done
fi
counter=$(($counter + 1))
fi
done
#!/bin/bash
getent passwd | awk -F: '{printf "%s\t%s\n",$1, $6}'| while read -r user home
do
if [ -d ${home}/public_html ] ; then
echo ${user}
fi
done
This should work irrespective of use of /etc/passwd or ldap ...

Directory checking in Linux

I am trying to write a script shell that takes two arguments as directory names, and determines if Directory 1 contains Directory 2 or vice versa. And also if there is no relationship between them.
I know the command to check if a directory exists is find -type d, however i was a bit confused as how to check and parse then names. I know i would need if-else loops, just not sure how to check for the conditions?
find won't be needed.
Something similar to this (but not guaranteeing directory name with spaces or some special characters.):
if [ "$dir1" == "$dir2" ]; then
echo "$dir1 == $dir2";
exit;
fi
if grep -E -q "^$dir2" <<< $dir1; then
echo "$dir1 is contained by $dir2."
exit
fi
if grep -E -q "^$dir1" <<< $dir2; then
echo "$dir2 is contained by $dir1.";
fi
However, this does not deal with symbolic links. For example, sym1 -> /usr/local/bin and sym2 -> /usr/local, apparently, sym2 contains sym1.
In addition, this does not deal with strange looking directory names, like /usr/local/./bin, which is the same as /usr/local/bin, or even /usr/local/../bin, which is the same as /usr/bin
--- Update ---
DevSolar metioned that readlink -e can be used to resolve the symbolic link. In my test, it also resolves the strange looking directory names like those with . and ... Thanks to DevSolar.
Do you want this?
if [ -d $1 ];then
a=`find $1 -type d -name $2`
if [ $a ];then
echo "$1 has $2"
else
echo "$1 does NOT has $2"
fi
fi
if [ -d $2 ];then
b=`find $2 -type d -name $1`
if [ $b ];then
echo "$2 has $1"
else
echo "$2 does NOT has $1"
fi
fi
This will do the trick I think,
find -name directory1 |grep directory2
or vice-versa, then use
echo $?
it will give 0 for success and 1 for failure.

Shell Scripting: Print directory names and files with specifics

In my script, I am asking the user to input a directory and then list all the files in that specific directory. What I want to do with that is to make the display a little better in which I would be able to display a "/" if the item in the directory is another directory and if it is an executable file (not an executable directory), print with a **".
This is what I have:
echo “Directory: “
read thing
for var123 in $thing*
do
echo $var123
done
In a directory I have a few folders and a few scripts that have the execute permission. when I run the script I want to say
/folder1/subfolder1/
/folder1/subfolder2/
/folder1/file1*
/folder1/file2*
I am new to this and have no clue what I am doing. Any help will be greatly appreciated.
You might want to check and make sure the user inputs something that ends in a / first.
e.g.
[[ $thing =~ '/'$ ]] || thing="$thing/"
Also check if it exists
e.g.
[[ -d $thing ]] || exit 1
Then for checking if it's a directory use the -d test as above. To check if executable file use -x. So putting that all together, try:
#!/bin/bash
echo “Directory: “
read thing
[[ $thing =~ '/'$ ]] || thing="$thing/"
[[ -d $thing ]] || exit 1
for var123 in "$thing"*
do
if [[ -f $var123 && -x $var123 ]]; then
echo "$var123**"
elif [[ -d $var123 ]]; then
echo "$var123/"
else
echo "$var123"
fi
done
ls -F is your friend here - if you want to do it for the current directory:
ls -F
If you want to do it for all files & subfolders of the current directory:
find * -exec ls -Fd {} \;
... and for a given directory:
echo "Directory: "
read DIR
find $DIR/* -exec ls -Fd {} \;
Edit: ls -F will append a / to directories and a * to executables. If you want ** instead, just use sed to replace them:
find $DIR/* -exec ls -Fd {} \; | sed 's/\*$/&&/'
And this approach works in all shells, not just bash.

Md5 Hash to identify and archive images

This is my first ever bash script and I am trying to iron out all of the creases and make the script run nicely. The script is to archive all of the specified .jpg files that it finds in multiple directories on a HDD/Flash drive. There are files with the same name but different content so I have used an Md5 sum to hash them.
I am getting the directory does not exist error in Geany but it runs fine from command bar missing out two of the images. I have tried everything I can think of to fix it. Is it messy code that is doing this?
#!/bin/sh
if [ ! -d "$1" ]; then
echo Directory "$1" cannot be found. Please try again.
exit
fi
if [ $# -eq 1 ]; then
echo "usage: Phar image_path archive_path"
exit
fi
if [ -d "$2" ]; then
echo "archive exists"
else
echo "the directory 'archive' does't exist. Creating directory 'archive'."
mkdir -p ~/archive
fi
find $1 -iname "IMG_[0-9][0-9][0-9][0-9].JPG" | cat > list.txt
[ -f ~/my-documents/md5.txt ] && rm md5.txt || break
while read line;
do md5sum $line | xargs >> md5.txt
done < list.txt
sort -k 1,1 -u md5.txt | cat > uniquemd5.txt
cut -d " " -f 2- uniquemd5.txt > uniquelist.txt
sort uniquelist.txt -r -o uniquelist.txt
for line in $(cat uniquelist.txt)
do
file=$(basename $line) path="$2/file"
if [ ! -f $path ];
then
cp $line $2
else
cp $line $path.JPG
fi
done
You haven't guarded against spaces in the folder and file names everywhere.
For instance:
cp $line $2
should be:
cp "$line" "$2"
You should start by eliminating these spaces as a source to your error by evaluating each variable you are referencing and adding ""'s.
If you still get the error please provide us with the arguments used and which directory that does not exist.

Resources