Remix.run Logo
wahern 5 hours ago

I find it easier to understand in terms of the Unix syscall API. `2>&1` literally translates as `dup2(1, 2)`, and indeed that's exactly how it works. In the classic unix shells that's all that happens; in more modern shells there may be some additional internal bookkeeping to remember state. Understanding it as dup2 means it's easier to understand how successive redirections work, though you also have to know that redirection operators are executed left-to-right, and traditionally each operator was executed immediately as it was parsed, left-to-right. The pipe operator works similarly, though it's a combination of fork and dup'ing, with the command being forked off from the shell as a child before processing the remainder of the line.

Though, understanding it this way makes the direction of the angled bracket a little odd; at least for me it's more natural to understand dup2(2, 1) as 2<1, as in make fd 2 a duplicate of fd 1, but in terms of abstract I/O semantics that would be misleading.

jez 4 hours ago | parent | next [-]

Another fun consequence of this is that you can initialize otherwise-unset file descriptors this way:

    $ cat foo.sh
    #!/usr/bin/env bash

    >&1 echo "will print on stdout"
    >&2 echo "will print on stderr"
    >&3 echo "will print on fd 3"

    $ ./foo.sh 3>&1 1>/dev/null 2>/dev/null
    will print on fd 3
It's a trick you can use if you've got a super chatty script or set of scripts, you want to silence or slurp up all of their output, but you still want to allow some mechanism for printing directly to the terminal.

The danger is that if you don't open it before running the script, you'll get an error:

    $ ./foo.sh
    will print on stdout
    will print on stderr
    ./foo.sh: line 5: 3: Bad file descriptor
47282847 4 hours ago | parent [-]

Interesting. Is this just literally “fun”, or do you see real world use cases?

jez 2 hours ago | parent | next [-]

I have used this in the past when building shell scripts and Makefiles to orchestrate an existing build system:

https://github.com/jez/symbol/blob/master/scaffold/symbol#L1...

The existing build system I did not have control over, and would produce output on stdout/stderr. I wanted my build scripts to be able to only show the output from the build system if building failed (and there might have been multiple build system invocations leading to that failure). I also wanted the second level to be able to log progress messages that were shown to the user immediately on stdout.

    Level 1: create fd=3, capture fd 1/2 (done in one place at the top-level)
    Level 2: log progress messages to fd=3 so the user knows what's happening
    Level 3: original build system, will log to fd 1/2, but will be captured
It was janky and it's not a project I have a need for anymore, but it was technically a real world use case.
jas- 2 hours ago | parent | prev | next [-]

Red hat and other RPM based distributions recommended kickstart scripts use tty3 using a similar method

post-it 3 hours ago | parent | prev [-]

Multiple levels of logging, all of which you want to capture but not all in the same place.

skydhash 2 hours ago | parent [-]

Wasn't the idiomatic way the `-v` flag (repeated for verbosity). And then stderr for errors (maybe warning too).

emmelaich 5 hours ago | parent | prev | next [-]

Yep, there's a strong unifying feel between the Unix api, C, the shell, and also say Perl.

Which is lost when using more modern or languages foreign to Unix.

tkcranny 5 hours ago | parent [-]

Python too under the hood, a lot of its core is still from how it started as a quick way to do unixy/C things.

kccqzy 4 hours ago | parent | prev | next [-]

And just like dup2 allows you to duplicate into a brand new file descriptor, shells also allow you to specify bigger numbers so you aren’t restricted to 1 and 2. This can be useful for things like communication between different parts of the same shell script.

niobe an hour ago | parent | prev | next [-]

I find it very intuitive as is

ifh-hn 4 hours ago | parent | prev [-]

Haha, I'm even more confused now. I have no idea what dup is...

jpollock 4 hours ago | parent [-]

There are a couple of ways to figure out.

open a terminal (OSX/Linux) and type:

    man dup
open a browser window and search for:

    man dup
Both will bring up the man page for the function call.

To get recursive, you can try:

    man man unix
(the unix is important, otherwise it gives you manly men)
Bender 4 hours ago | parent [-]

otherwise it gives you manly men

That's only just after midnight [1][2]

[1] - https://www.youtube.com/watch?v=XEjLoHdbVeE

[2] - https://unix.stackexchange.com/questions/405783/why-does-man...