Linux - NewbieThis Linux forum is for members that are new to Linux.
Just starting out and have a question?
If it is not in the man pages or the how-to's this is the place!
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I've used basic linux for a while, really basic. Now I need to write a simple script that will list all my users password status to a file.
I have a list of users (userlist.txt) and need to read that file and do chage -l user.
If you could tell me the steps are doing, it would help me to try other scripts. I'm using bash shell.
Thanks, Karen
If you enter 'chage' at the command line, it tells you this about its usage
Code:
~ $ chage
Usage: chage [options] [LOGIN]
Options:
-d, --lastday LAST_DAY set date of last password change to LAST_DAY
-E, --expiredate EXPIRE_DATE set account expiration date to EXPIRE_DATE
-h, --help display this help message and exit
-I, --inactive INACTIVE set password inactive after expiration
to INACTIVE
-l, --list show account aging information
-m, --mindays MIN_DAYS set minimum number of days before password
change to MIN_DAYS
-M, --maxdays MAX_DAYS set maximim number of days before password
change to MAX_DAYS
-W, --warndays WARN_DAYS set expiration warning days to WARN_DAYS
~ $
To do what you ask wouldn't need a formal script, just this command
Code:
chage -l < '/path/to/userlist.txt'
where 'chage -l' shows account aging information
< means following string is your input file path
Quotes on the file path are necessary only if it includes embedded whitespace (spaces, tabs, newlines), and may be single or double in this case
/path/to/ is the path to the directory containing the file of user names, not needed if that is the current directory
And it would show out put like this
Code:
~ $ chage -l g
Last password change : Jun 04, 2012
Password expires : never
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 99999
Number of days of warning before password expires : 7
~ $
for each user name in userlist.txt (g is my user name)
To send the output to a file instead of printing it on the console, instead use the command as
The > prompt is the shell waiting for you to finish the command. It has only encountered three quotes so far, it's expecting a fourth. You can use Ctrl+C to cancel the command, then you can fix it and run it again.
This is giving the results that prompted me to post this question. But I do appreciate the help. The data in the results.txt file is the same listing that is in the userlist.txt. So it's just outputting the file it read.
It's just outputting the same file it read because apparently none of the users exist on the system, so all you get is the "echo $user" with blank output from the chage -l.
This is how the output should look, if the users actually exist:
Code:
# cat users.txt
user1
user2
user3
# while read user; do echo $user; chage -l $user; done < users.txt > results.txt
# cat results.txt
user1
Last password change : Mar 01, 2010
Password expires : never
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 99999
Number of days of warning before password expires : 7
user2
Last password change : Jul 02, 2012
Password expires : never
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 99999
Number of days of warning before password expires : 7
user3
Last password change : Apr 03, 2012
Password expires : never
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 99999
Number of days of warning before password expires : 7
#
I must be doing something incorrectly. I have over 150 users, all exist in the /users/ directory. If I manually do chage -l user1, I get the correct output. But if user1 is in the list /users/userlist.txt, it doesn't output anything, except the name of the user. I've checked for spaces, and there aren't any. I could see one or two typos' in the list, but not all of them.
I must be doing something incorrectly. I have over 150 users, all exist in the /users/ directory. If I manually do chage -l user1, I get the correct output. But if user1 is in the list /users/userlist.txt, it doesn't output anything, except the name of the user. I've checked for spaces, and there aren't any. I could see one or two typos' in the list, but not all of them.
How did you make the list? Maybe it has some weird EOL terminators that are making their way into the chage -l call?
~ $ cat fred.txt
g
Root
q
~ $ mapfile < fred.txt x
~ $ y=${#x[@]}
~ $ for ((i=0; i<y; i++)); do chage -l ${x[$i]}; done
Last password change : Jun 04, 2012
Password expires : never
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 99999
Number of days of warning before password expires : 7
chage: user 'Root' does not exist in /etc/passwd
chage: user 'q' does not exist in /etc/passwd
~ $
mapfile is a bash internal that creates an array (x) from an input file (fred.txt) using an entire line as the content of each cell. Usually it is used with a '-t' option which omits the newline character from each line when building the array. Without '-t' each cell includes the newline, and I believe it was the lack of this which caused the failure of other methods.
y=${#x[@]} gets the number of cells in array x
The 'for' loop delivers the content of each cell in array x to chage, including the linebreak. That is, it simulates exactly what happens when you enter the username at the console, and press Return.
Mine is a single user machine, so /etc/passwd has only my user entry in it, hence the rejection of Root and q
Following is the 'for' loop rewritten to send chage's output to a file, o.txt. >> is used because we need each user output appended to the file
Code:
~ $ for ((i=0; i<y; i++)); do chage -l ${x[$i]} >> o.txt; done
chage: user 'Root' does not exist in /etc/passwd
chage: user 'q' does not exist in /etc/passwd
~ $ cat o.txt
Last password change : Jun 04, 2012
Password expires : never
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 99999
Number of days of warning before password expires : 7
~ $
Apparently the non-existent users are being rejected by bash and never presented to chage
And as chage doesn't bother to tell you the user name its dealing with, you might want to make the 'for' loop something like
Code:
for ((i=0; i<y; i++)); do chage -l ${x[$i]} >> o.txt; echo "Above Entry for User ${x[$i]}"; done
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.