I'm just wondring how to know which instruction we normally put first in a shell command ? for example, why the command:
ls -l file_doesnot_exists > /dev/null 2>&1
is working, while this command :
ls -l 2>&1 file_doesnot_exists > /dev/null
is not
CodePudding user response:
Note:
- The question is tagged
linux
, which means thatls
is not a built-in alias of PowerShell's ownGet-ChildItem
cmdlet (which applies on Windows only) and instead refers to the standard/bin/ls
Unix utility.
In PowerShell there is no difference between your commands, because the order of redirections does NOT matter.
All targeted output streams always retain their identity: any redirection of a stream affects any other redirections to the same stream in the same command.
Therefore, neither of your commands work as intended and produce no output, because while
2>&1
redirects the error stream (2
) into the success output stream (1
), the latter's output is ultimately discarded, due to> /dev/null
(>
is the same as1>
), including the redirected error-stream output.
By contrast, in POSIX-compatible shells such as Bash, the order of redirections DOES matter:
ls -l 2>&1 file_doesnot_exists > /dev/null
WORKS as intended:2>&1
redirects stderr output to the original stdout.- The later redirection of stdout (
>
is the same as1>
) has no effect on2>&1
- The net effect is that only stderr lines print to stdout, while stdout lines are discarded (by the redirection to
/dev/null
).
By contrast,
ls -l file_doesnot_exists > /dev/null 2>&1
DOES NOT and produces no output:> /dev/null
redirects stdout to/dev/null
, i.e. effectively discards stdout output.Because
2>&1
comes later in the command,1
refers to the already redirected stdout, so that stderr output too is discarded.
See this answer for more information.
CodePudding user response:
Assuming this is being ran in PowerShell Core (since the tags indicate it is), it's safe to assume you're confusing bash commands with PowerShell cmdlets. In PowerShell, you have to be mindful of Terminating, and Non-Terminating errors.
Simply put, the reason why ls -l 2>&1 file_doesnot_exists > /dev/null
doesn't work is because, ls
- alias for Get-ChildItem
- produces a terminating error that halts the rest of the execution since it is missing an argument. This is demonstrated in a Try {...} catch {...}
statement where the catch
block "catches" terminating errors.
try {
ls -l
}
catch {
"it no workie"
}
Since ls
is an alias to Get-ChildItem
, the -L
parameter defaults to -LiteralPath
where it's now expecting a path and it's erroring out when ran since it wasn't provided.