Comment by goku12

14 hours ago

This is probably one of the reasons why many find POSIX shell languages to be unpleasant. There are too many syntactical sugars that abstract too much of the underlying mechanisms away, to the level that we don't get it unless someone explains it. Compare this with Lisps, for example. There may be only one branching construct or a looping construct. Yet, they provide more options than regular programming languages using macros. And this fact is not hidden from us. You know that all of them ultimately expand to the limited number of special forms.

The shell syntactical sugars also have some weird gotchas. The &2>&1 question and its answer are a good example of that. You're just trading one complexity (low level knowledge) for another (the long list of syntax rules). Shell languages break the rule of not letting abstractions get in the way of insight and intuitiveness.

I know that people will argue that shell languages are not programming languages, and that terseness is important for the former. And yet, we still have people complaining about it. This is the programmer ego and the sysadmin ego of people clashing with each other. After all, nobody is purely just one of those two.

There must be a law of system design about this, because this happens all the time. Every abstraction creates a class of users who are powerful but fragile.

People who build a system or at least know how it works internally want to simplify their life by building abstractions.

As people come later to use the system with the embedded abstractions, they only know the abstractions but have no idea of the underlying implementations. Those abstractions used to make perfect sense for those with prior knowledge but can also carry subtle bias which makes their use error prone for non initiated users.

  • > Those abstractions used to make perfect sense for those with prior knowledge but can also carry subtle bias which makes their use error prone for non initiated users.

    I don't think 2>&1 ever made any sense.

    I think shell language is simply awful.

    • > I don't think 2>&1 ever made any sense.

      It's not that hard. Consider the following:

        $ command &2>&1
      

      The shell thinks that you're trying to run the portion before the & (command) in the background and the portion after the & (2>&1) in the foreground. There is just one problem. The second part (2>&1) means that you're redirecting stderr/fd2 to stdout/fd1 for a command that is to follow (similar to how you set environment variables for a command invocation). However, you haven't specified the command that follows. The second part just freezes waiting for the command. Try it and see for yourself.

        $ command 2>1
      

      Here the shell redirects the output of stderr/fd2 to a file named 1. It doesn't know that you're talking about a file descriptor instead of a filename. So you need to use &1 to indicate your intention. The same confusion doesn't happen for the left side (fd2) because that will always be a file descriptor. Hence the correct form is:

        $ command 2>&1
      

      > I think shell language is simply awful.

      Honestly, I wish I could ask the person who designed it, why they made such decisions.

  • I like abstractions when they hide complexity I don't need to see nor understand to get my job done. But if abstractions misdirect and confuse me, they are not syntactical sugar to me, but rather poison.

    (But I won't claim that I am always able to strike the right balance here)

  • Seems related to the Law of Leaky Abstractions?

    • It's not necessarily a leaky abstraction. But a lack of _knowledge in the world_.

      The abstraction may be great, the problem is the lack of intuitive understanding you can get from super terse, symbol heavy syntax.

make 2>&1 | tee m.log is in my muscle memory, like adding a & at the end of a command to launch a job, or ctrl+z bg when I forget it, or tar cfz (without the minus so that the order is not important). Without this terseness, people would build myriads of personal alias.

This redirection relies on foundational concepts (file descriptors, stdin 0, stdout 1, stderr 2) that need to be well understood when using unix. IMO, this helps to build insight and intuitiveness. A pipe is not magic, it is just a simple operation on file descriptors. Complexity exists (buffering, zombies), but not there.

  • Are you sure you understood the comment you replied to?

    I agree that 2>&1 is not complex. But I think I speak for many Bash users when I say that this idiom looks bad, is hard to Google, hard to read and hard to memorize.

    • It’s not like someone woke up one morning and decided to design a confusing language full of shortcuts to make your life harder. Bash is the sum of decades of decisions made, some with poor planning, many contradictory, by hundreds of individuals working all over the world in different decades, to add features to solve and work around real world problems, keep backwards compatibility with decades of working programs, and attempt to have a shared glue language usable across many platforms. Most of the special syntax was developed long before Google existed.

      So, sure, there are practical issues with details like this. And yet, it is simple. And there are simple methods for learning and retaining little tidbits like this over time if you care to do so. Bash and its cousins aren’t going away, so take notes, make a cheat sheet, or work on a better replacement (you’ll fail and make the problem worse, but go ahead).

      2 replies →

Shell is optimized for the minimal number of keystrokes (just like Vim, Amadeus and the Bloomberg Terminal are optimized for the minimum number of keystrokes. Programming languages are primarily optimized for future code readability, with terseness and intuitiveness being second or third (depending on language).

  ? (defun even(num) (= (mod num 2) 0))
  ? (filter '(6 4 3 5 2) #'even)

I'm zero Lisp expert and I don't feel comfortable at all reading this snippet.

  • This:

    > I'm zero Lisp expert

    and this:

    > I don't feel comfortable at all reading this snippet

    are related. The comfort in reading Lisp comes from how few syntactic/semantic rules there are. There's a standard form and a few special forms. Compare that to C - possibly one of the smallest popular languages around. How many syntactical and semantic rules do you need to know to be a half decent C programmer?

    If you look at the Lisp code, it has just 2 main features - a tree in the form of nested lists and some operations in prefix notation. It needs some getting used to for regular programmers. But it's said that programming newbies learn Lisps faster than regular programming languages, due to the fewer rules they have to remember.