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 thatlsis not a built-in alias of PowerShell's ownGet-ChildItemcmdlet (which applies on Windows only) and instead refers to the standard/bin/lsUnix 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>&1redirects 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/nullWORKS as intended:2>&1redirects 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>&1DOES NOT and produces no output:> /dev/nullredirects stdout to/dev/null, i.e. effectively discards stdout output.Because
2>&1comes later in the command,1refers 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.
