Shell – Why does ‘nohup command >& /dev/null’ seem to “work” in some shells

io-redirectionnohupshell

I edited an answer on Ask Ubuntu that was suggesting the following

nohup gedit >& /dev/null & 

When they actually meant

nohup gedit &> /dev/null & 

The latter correctly redirects both stderr and stdout to /dev/null. I was expecting the former to either create a file called & or, more likely, to give an error as it does for other cases:

$ echo "foo" >& 
bash: syntax error near unexpected token `newline'

Instead, it seems to work in exactly the same way as the former, a gedit window appears and no error message is printed.

I should also note that this is shell specific:

  • bash (4.2.45(1)-release), zsh (5.0.2), csh (deb package version: 20110502-2) and tcsh (6.18.01) : works as described above, no error message, no files created.

  • dash (0.5.7-3):

    $ nohup gedit >& /dev/null & 
    $ dash: 2: Syntax error: Bad fd number
    
  • ksh (93u+ 2012-08-01): fails, but a process is apparently started (1223) though no gedit window appears:

    $ nohup gedit >& /dev/null & 
    [1] 1223
    $ ksh: /dev/null: bad file unit number
    
  • fish (2.0.0):

    > nohup gedit >& /dev/null & 
    fish: Requested redirection to something that is not a file descriptor /dev/null
    nohup gedit >& /dev/null & 
                   ^
    

So, why does this command simply run with no errors (and no output file created) in some shells and fail in others? What is the >& doing in the apparently special case of nohup? I am guessing that >& /dev/null is being interpreted as >&/dev/null but why isn't the space causing an error in these shells?

Best Answer

nohup gedit &> /dev/null

is POSIX syntax and is the same as:

nohup gedit &
> /dev/null

That is run nohup gedit in background and then do a > /dev/null redirection without running a command.

nohup gedit >& /dev/null

is not POSIX syntax and is the csh way to redirect both stdout and stderr to /dev/null. csh doesn't have the 2>&1 operator as found in Bourne, so it's the only way csh has to redirect stderr.

zsh (as often) also provides with the csh syntax, but it also supports the x>&y fd duplication operator of the Bourne shell, which means there's a conflict there.

ls >&file

redirects ls's stdout and stderr to file, but if the file is 2, you've got a problem as

ls >&2

means redirect stdout to the resource pointed to by fd 2 (dup(2, 1)). So you need to write it:

ls >& ./2

if you wanted to redirect both the stdout and stderr of ls into a file called 2 in the current directory; or use the standard syntax.

bash initially did no understand >&, but it introduced the &> operator instead for that, breaking POSIX compliance in the process (though it's unlikely a script would use cmd &> xxx).

ksh copied that operator in ksh93t+ in 2009, mksh in R35 in 2008 (disabled in posix mode) but not >&.

bash added support for >& in 2.05.

busybox sh added support for both &> and >& in 1.13 (2008).

Neither >& nor &> as meaning redirect stdout and stderr are POSIX/Bourne.

If you want to redirect both stdout and stderr portably, the syntax is

cmd > file 2>&1
Related Question