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?

  • 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).

  • 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. 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)
  • 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
  • 1
    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 clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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