Hacker News new | past | comments | ask | show | jobs | submit login

Re: ">file 2>&1" vs. "2>&1 >file"

I tend to think "a>&b" as an assignment to a stream: stream[a]=stream[b]. This way it's easier to understand why the ordering matters:

    >file 2>&1 means stream[1]=file; stream[2]=stream[1];
    2>&1 >file means stream[2]=stream[1]; stream[1]=file;



Yes, that's a good way to think of it. Because under the hood redirects use the dup2() syscall (with some elaboration).

What is dup2()? It's basically an assignment of the things that file descriptors point to. Why not use regular assignment? Because the things they point to live in the kernel's memory, not your own address space :)

Here I describe file descriptors as "pointers" from user space into the kernel. They are integers and not literal pointers because they're in a different address space.

Three Comics For Understanding Unix Shell: https://www.oilshell.org/blog/2020/04/comics.html

So yes redirects are a very low level and somewhat confusing syntax, and you have to understand how the kernel works to really understand them.

----

Although I didn't really understand this until I implemented a shell, and instead I mostly used these canned patterns:

    sort < myfile
    mycmd 2>&1
    mycmd 2>&1 | wc -l  # stdout and stderr to pipe
    mycmd >file.txt 2>&1  # stdout and stderr to file
    echo error >&2 
That's about all you need. Related:

Avoid Directly Manipulating File Descriptors in Shell: https://www.oilshell.org/blog/2017/08/12.html (all usages of say 4>&5 can be done simply by regular direction of shell FUNCTIONS, no need to juggle them manually)


To define this behavior as "redirection" is pretty questionable from a UX perspective. This was clearly invented by someone who is so smart they don't even realize how much less smart everyone else is. That, or it was just the easiest way to do it back then...


I'm curious why my post was downvoted. If there are people out there who think that file descriptor duplication is intuitive behavior for shell redirection, I would love to hear about it! I don't learn anything from silent downvotes.


It's not intuitive, but it was easy to implement :) There are a lot of things in Unix and Unix shell like that.

I learned that parsing here docs is another one of them! It's a weird syntax, and I came up with something clever for parsing it. And then I realized there is a simple algorithm that kind of "falls out" of the AST.

https://www.oilshell.org/blog/2016/10/17.html

The famous "worse is better" essay on Unix talks about implementation simplicity vs. interface simplicity. Unix favors implementation simplicity!


are you saying that ordering counts, because I don't think it does.

>file = redirect stdout to file 2>&1 = redirect stderr to stdout which is being redirect to file

trying to state they = something seems like it would be confusing as they don't equal as much as just being re-routed.

Edit: I've never seen it described as TFA, but would have put money that I have done it in either order and worked without issue. i guess it's a good thing i'm not a gambler


Ordering counts! This, for me, was key to understanding the particular example above.

One of the challenges in the LPIC-1 study material I waaay back in 2008 was something like, how do you swap the stdout / stdin around? The solution required the use of a 3rd file descriptor, and an understanding that the order of ops was important.

Edit: let me embarrass myself by fucking this up, from my phone, without checking in a terminal...

run.sh 3>&1 1>&2 2>&3

So:

1. You point fd3 to "the thing that stdout is pointing at" (which keeps a safe copy of stdout during the juggling exercise)

2. Next you point fd1 at "the thing that stderr points to". So phase one is complete: stdout will now show the contents of stderr.

3. Finally you point fd2 at the copy of fd1's target. This completes the task, since stderr will now show the contents of stdout

We don't really care what happens to fd3. But if we did, we could fix that by directing it to /dev/null at the end. Again, showing how important the ordering is.


> We don't really care what happens to fd3. But if we did, we could fix that by directing it to /dev/null at the end. Again, showing how important the ordering is.

it's good practice to close extra FDs for children who are not expecting it. poorly designed applications may misbehave if provided with unexpected additional FDs. you shouldn't use /dev/null for this purpose, but instead actually close it with 3>&-.


It's why I prefer to use &> and |&

Now the article tells me not to use them, but the justification [1] is a broken link. I assume [2] is the correct link, but the justification there is not convincing to me. It says other shells that don't implement them parse them differently, which is tautologically correct, and is also already the case for every other non-POSIX feature in bash and every other shell. So I'm not sure why these two operators should be treated differently.

[1]: https://wiki.bash-hackers.org/howto/obsolete

[2]: https://wiki.bash-hackers.org/scripting/obsolete


See also: Zsh.

POSIX compatibility is a great thing to have available, when you need it. But my personal scripts and one-offs do not need to be POSIX-compatible!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: