Home > Blockchain >  why the command; ls -l file_doesnot_exists > /dev/null 2>&1 is working while; ls -l 2>&1 fi
why the command; ls -l file_doesnot_exists > /dev/null 2>&1 is working while; ls -l 2>&1 fi

Time:08-27

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 that ls is not a built-in alias of PowerShell's own Get-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 as 1>), 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 as 1>) has no effect on 2>&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.

  • Related