Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I created an account "diag" and set it as expired (usermod --expiredate 1). Then I have a script which I want to run to log into it, so in the script I use the following command:

su -s /bin/bash - diag

This outputs like so:

Your account has expired; please contact your system administrator
su: Authentication failure

And then I'm able to use the account, as expected.

I want to suppress the first three lines, the warning about the expired account. I tried adding 2> /dev/null to the end of the command, but that suppresses all the output from bash; I just get a blank response, and I can type commands into it and see the result from them, but I see no bash prompt. I tried adding just > /dev/null and that does nothing.

So I've deduced that apparently su is piping all its output over stderr. How can I get su to just suppress those first three lines, but otherwise act normally as if the account weren't expired?

share|improve this question
What exactly are you trying to do? Beware the XY problem. – terdon Oct 4 '12 at 17:29
I am trying to open a bash prompt for an expired user. – Ricket Oct 4 '12 at 17:32

As far as I can tell, user account expiration and lock is functionally the same thing; login attempts will fail, SSH attempts will fail, etc. At least for my purposes they are the same.

So, in my script, I now detect whether the user is expired, and if so, lock the user and set the expiration to 'never'.

It looks something like this:

# Takes 1 parameter, the username to check
# Returns 0 if the user is expired, or 1 if it is not expired.
function userExpired()
    # These day values are just numbers, the number of days since the epoch.
    local expireDay=`grep $1 /etc/shadow | cut -d: -f8`

    # If diag has no expiration date, it will be empty.
    if [[ "$expireDay" -eq "" ]] ; then
        return 1

    local today=`perl -e 'print int(time/(60*60*24))'`
    local daysUntilExpire=`echo $expireDay - $today | bc`

    [[ $daysUntilExpire -lt 0 ]]

# Check if the diag user is expired and if so, lock and unexpire it.
userExpired diag && {
    usermod --lock --expiredate -1 diag

I wrote the userExpired function from code found in this forum post (modified to fit my code style and better variable naming).

share|improve this answer
Caution: --lock and --expiredate are subtly different. Lock prevents password login (typically by prepending ! to the password hash in the passwd or shadow file) but a user who previously established SSH keys (for example) will still be able to gain access. In this case, this is unlikely, since your diag user has been custom made, but I note this here for completeness. The expiredate approach is still the recommended approach if you truly want to disable login, but still allow su and friends to work. – Cosmic Ossifrage Jan 24 '15 at 17:24

Redirected stderr to stdout

su -s /bin/bash - diag 2>&1 >/dev/null

This one I haven't tried but expect should work (will update soon once home)

discard=$(su -s /bin/bash - diag)
share|improve this answer
How does this differ from simply redirecting stderr to /dev/null with 2> /dev/null? – Ricket Oct 4 '12 at 18:15
that wont suppress all the output from bash ;) , however I havent tested these, I would appreciate if you can tell what you observed... – perilbrain Oct 4 '12 at 18:18
I think we're having a misunderstanding. I don't want all output suppressed; I just want the su expiration warning to not be displayed. – Ricket Oct 4 '12 at 18:29

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.