Please explain this script (from ABSG. Ch. 20):exec 3>&1                              # Save current value of stdout.ls -l 2>&1 >&3 3>&- | grep bad 3>&-    # Close fd 3 for 'grep' (but not 'ls').#              ^^^^   ^^^^exec 3>&-                              # Now close it for the remainder of the scriptCurrently I imagine how it works:script connects fd/3 output to stdoutpipeline connects stdout of ls to stdin of grep (fd/3 is inherited by both processes)redirerection of stderr of ls to stdoutstdout of ls is changed to fd/3 (so grep process has no more ls output, only errors)fd/3 is closed for lsIs this the exactly sequence of redirections?Can't understand why I see output of ls if there are no errors and we close fd/3 where stdout is redirected.What is the purpose of closing fd/3 for grep process (grep bad **3>&-**)?
Pipeline and redirection understanding
bash;io redirection
It helps a bit if you think the file descriptors as variables that accept a file as a value (or call it an i/o stream) and the order they appear is the order of their evaluation.What happens in the above example is:1) The script starts (as per default and unless otherwise inherited) with the followingfd/0 = stdin    # that's the keyboardfd/1 = stdout   # that's the screenfd/2 = stderr   # the screen again, but different stream2) The exec command translates to declaring a new variable and assigning a valuefd/3 = fd/1  # same as stdoutSo now, two file descriptors have the value stdout, i.e. both can be used to print to the screen.3) before ls is executed and inherits all open file descriptors, the following setup happensls.fd/1 = grep.fd/0    # pipe gets precedence, ls.fd/1 writes to grep.stdinls.fd/2 = ls.fd/1      # ls.fd/2 writes to grep.stdin ls.fd/1 = ls.fd/3      # ls.fd/1 writes to stdoutls.fd/3 = closed       # fd/3 will not be inherited by `ls`fd/3 has served the purpose of keeping the stdout value long enough to return it to fd/1. So now everything that ls sends to fd/1 goes to stdout and not grep's stdin.The order is important, e.g. if we'd run ls -l >&3 2>&1 3>&-, ls.fd/2 would write to stdout instead of grep's stdin.4) fd/3 for grep is closed and not inherited. It would be unused anyway. grep can only filter error messages from lsThe example provided in ABSG is probably not the most helpful and the comment Close fd 3 for 'grep' (but not 'ls') is a bit misleading. You can interpret it as: for the ls, pass the value of ls.fd/3 to ls.fd/1 before unsetting so it won't get closed.