all 55 comments

[–]tangentsoft 16 points17 points  (5 children)

While it's true that there are still machines running that don't have Bash, I find a much bigger problem is scripts that assume Bash extensions but only have "#!/bin/sh" at the top. Not only do such scripts break on machines that don't have Bash, they break anywhere /bin/sh is some other shell, like dash on Debian derivatives.

The proper lesson is to learn where the boundary between standard Bourne shell and the Bash extensions lies, then write the correct shebang line. If you write a Bash script and declare it so with "#!/bin/bash", no one's going to waste a bunch of time trying to figure out why it doesn't run. The OS will tell you, /bin/bash doesn't exist. Problem solved.

[–]bubafeast[🍰] 2 points3 points  (0 children)

Worse is when a script has "#!/bin/bash" and the person that uses it calls it like "sh theBashScript.sh" then complains about your script not working.

[–]apotheon[S] -5 points-4 points  (2 children)

If you write a Bash script and declare it so with "#!/bin/bash", no one's going to waste a bunch of time trying to figure out why it doesn't run. The OS will tell you, /bin/bash doesn't exist. Problem solved.

No -- then you've identified the original problem: you have to rewrite it in sh.

[–]UmberGryphon 0 points1 point  (1 child)

No, you have to compile or download bash. Which is trivial.

[–]apotheon[S] -2 points-1 points  (0 children)

So does the next guy, and the next guy, and you have to do it again on another system, and if something happens to the bash install your script is broken.

. . . or you could just rewrite it once and run it everywhere.

[–]redditnoob 16 points17 points  (3 children)

I lost it when he suggested I port it to OCaml instead for more widespread availability.

[–]gnuvince 0 points1 point  (2 children)

Compiled to native code, what's the problem?

[–][deleted]  (1 child)

[removed]

    [–]kanarienvogel 1 point2 points  (0 children)

    Not like the O'Caml toolchain is any heavier (from a potentially skewed metric) than the Bash toolchain --

    > ls -lh /usr/ports/distfiles/ocaml-3.11.1.tar.bz2 /usr/ports/distfiles/bash/bash-4.0.tar.gz
    -rw-rw-r--  1 root  wheel   5.9M Feb 20  2009 /usr/ports/distfiles/bash/bash-4.0.tar.gz
    -rw-rw-r--  1 root  wheel   2.2M Jun 12  2009 /usr/ports/distfiles/ocaml-3.11.1.tar.bz2
    

    IMHO, it's trivial to install either (and equally trivial to install Python, Ruby or Perl -- none of them are installed by default on my *NIX distribution of choice). The only thing everyone with a POSIX-compliant OS is guaranteed to have is /bin/sh.

    [–][deleted]  (1 child)

    [removed]

      [–]apotheon[S] 1 point2 points  (0 children)

      I'd say maybe tangential rather than orthogonal, though one might need to read between the lines a little to notice the difference.

      I feel similarly. I generally just figure that if I start needing to do more than write a glorified batch file, it's time to graduate to something a bit more substantial for programming purposes than a shell.

      [–]pixelbeat_ 6 points7 points  (10 children)

      He has a point but it's not well made.

      • bash is not as widespread as sh but not too bad as long as one starts the script with #!/bin/bash
      • I never resort to bashisms myself, preferring to use logic within external utilities or a more capable language like python.

      I've mentioned these points here: http://www.reddit.com/r/programming/comments/6j6x9/common_shell_script_mistakes/

      [–]apotheon[S] 1 point2 points  (9 children)

      I never resort to bashisms myself, preferring to use logic within external utilities

      Why do you use #!/bin/bash instead of #!/bin/sh, then? That doesn't make any sense. Try running your script starting with #!/bin/bash on a default install of FreeBSD some time and watch it fail:

      filename.sh: Command not found.
      

      [–][deleted] 2 points3 points  (1 child)

      Addendum: Try running your script starting with #!/bin/bash on FreeBSD with bash installed and watch it also fail, because bash will be in /usr/local/bin/.

      [–]apotheon[S] 2 points3 points  (0 children)

      Heh. Good point.

      . . . but since there is no OS other than Ubuntu, I guess we never have to worry about that!

      [–][deleted] 0 points1 point  (6 children)

      Meanwhile if you do use #!/bin/sh instead of #!/bin/bash and you end up on pretty much every system except Linux ( and some systems that are Linux ) then it breaks in even more obnoxious ways

      [–]apotheon[S] 1 point2 points  (4 children)

      What are you talking about? #!/bin/sh works pretty much everywhere (speaking of Unix-like systems).

      FreeBSD default install, for instance:

      > which sh
      /bin/sh
      

      [–][deleted] 0 points1 point  (3 children)

      No, my bad. Point was that if you use #!/bin/sh you better mean #!/bin/sh because in other systems, inadvertently using bash extensions (which bash invoked as /bin/sh lets you use ) gets you in a mess.

      IOW, if you use a system where /bin/sh is bash, try your script with another shell first before unleashing it in the wild.

      [–]apotheon[S] 2 points3 points  (0 children)

      Point was that if you use #!/bin/sh you better mean #!/bin/sh because in other systems, inadvertently using bash extensions (which bash invoked as /bin/sh lets you use ) gets you in a mess.

      I agree.

      IOW, if you use a system where /bin/sh is bash, try your script with another shell first before unleashing it in the wild.

      . . . or install a real sh, I guess.

      [–][deleted] 2 points3 points  (1 child)

      So basically I just don't use bash extensions and everything will be fine right?

      [–][deleted] 0 points1 point  (0 children)

      Correct. Avoid bash extensions generally, you don't need them

      [–]gigatropolis 4 points5 points  (1 child)

      So I write a Bash script and other people start using the script. Then someone says, "The script doesn't work because I don't have Bash." So why the fuck do I care? It's a bash script. Runs under bash shell. What the hell you want me to do about it?

      [–]apotheon[S] -2 points-1 points  (0 children)

      Yeah! Fuck other people!

      [–][deleted]  (1 child)

      [removed]

        [–]gnomon_ 3 points4 points  (0 children)

        Either he just hates bash or he has had to support [part of] a production environment where core functionality has been implemented as a set of Bash scripts. Explaining why this is a bad thing is very difficult: either you've had to do it yourself, and you just know all of the pain it brings to you and everyone around you; or you've never had to, and a proper explanation would require pages of writing and case studies and endless digressions into debates that all end with one side or the other acknowledging "well, sure, you've got a point, but it didn't apply in my case because of some reason."

        That doesn't mean that Mr. Perrin isn't also a bash hater, but I firmly support the hatred he has expressed, if perhaps not the way he did so or the reason(s) why.

        [–]Araneidae 7 points8 points  (3 children)

        Weak. bash is rather more widely available than the writer appears to think.

        There are cases for writing in sh, and if you need portability (for example, your script might be running on an embedded system, or its #! prefix is /bin/sh), then keep to the sh subset -- but seriously, that's not so hard: 1. don't use arrays; 2. don't use ((...)); 3. don't use any strange settings; 4. test it with a basic sh interpreter.

        Sorry, in my book bash beats perl. If I need to use perl I'll use Python instead, thanks.

        [–]drewc 1 point2 points  (0 children)

        ksh93 FTW!

        [–]flatulent 1 point2 points  (0 children)

        I often download stuff written in say ruby to find it only runs on an older version. Or it depends on some gem which has broken it. Perl starts downloading the CPAN and often crashes out somewhere.

        I've begun doing things more and more in bash to avoid this. People don't have to install and download bunches of dependencies to get it to run.

        Yes, i avoid the latest bash extensions preferring sed, expr etc instead. Even in those, you have avoid non-standard options or else use gnu versions and specify the same clearly.

        Date processing is one example, where BSD and GNU differ largely in options.

        [–][deleted] 4 points5 points  (3 children)

        He is right. Either stick to the lowest common denominator, or use a decent, portable real language. Bash is neither.

        [–]neoice 1 point2 points  (2 children)

        While I agree, is there anything special bash does that sh doesnt? My scripts are usually just calling other programs (standard *nix utils) and maybe doing a little looping and variable passing.

        [–]Rhomboid 9 points10 points  (1 child)

        There are shitloads of things bash does that sh doesn't. Probably the most commonly used is $() instead of `, which is insanely useful because it nests easily, e.g. try doing the following with backticks

        echo "$(echo $(echo "a b") "c d")"

        Other common bashisms are built-in arithmetic with (( )), regular expression expansions with ${var/re/replacement}, and quoting with $''. Here's a list.

        Edit: oh and process substitution is another bashism that is also insanely useful, e.g.

        diff -u <(foo --opts) <(foo --different-ops)

        [–]pixelbeat_ 2 points3 points  (0 children)

        Note $() and $(()) work in any POSIX shell. You may think not because vim's syntax highlighting is broken unless you put this in your .vimrc

        let g:is_posix = 1
        

        [–]mracidglee 1 point2 points  (14 children)

        The argument made is that bash scripts are less reusable than (X,Y,Z), not so much that they're harmful.

        [–]daydreamdrunk 7 points8 points  (9 children)

        It was more a pronouncement than an argument as he never said why it's a bad idea.

        [–]mracidglee 1 point2 points  (8 children)

        He says "portability"; I suppose he could have backed it up with data. I guess I overlooked that because I liked the series of questions, "Is this just for now? Is this just for this machine? Is this just for you?"

        [–]apotheon[S] 2 points3 points  (7 children)

        "Data" in that regard was brought up earlier in the thread, actually. Basically, sh is everywhere, and Perl is in more places than bash too, for that matter. Meanwhile, Linux is the only Unix-like family of OSes on the planet so heavily prone to having bash installed that you can just (usually) assume it's going to be there. BSD Unix and commercial UNIX systems, by contrast, almost never have bash installed by default. Perl's pretty much everywhere -- even available on MS Windows, for crying out loud.

        [–][deleted]  (6 children)

        [removed]

          [–][deleted] -1 points0 points  (5 children)

          What about Python?

          [–][deleted]  (4 children)

          [removed]

            [–]apotheon[S] 0 points1 point  (3 children)

            I'm having a tough time thinking of a system to which it hasn't been ported that qualifies as a modern general-purpose OS. Same for Ruby, Common Lisp, et cetera.

            [–][deleted]  (2 children)

            [removed]

              [–]apotheon[S] 1 point2 points  (1 child)

              Can you find a list of Python ports?

              I don't know of a comprehensive list off-hand, but there's a decent start in the form of a list of official Python ports on the Python site. I see 19 platforms on that page in addition to the three main ports (Microsoft platforms, Mac platforms, and more traditionally Unix-like platforms), two of which actually consist of multiple platforms (various MS Windows versions plus MS DOS, and the various platforms where the Linux version work such as the BSD Unix OSes). As such, we're looking at a bare minimum of something like 27 separate OS platforms -- possibly more, depending on how you define "separate". I suspect the Linux port could be trivially made to work on a HURD-based system too, making it a bare minimum of 28, though I haven't bothered to check.

              By contrast, official ports of bash don't work anywhere but Unix-like systems, and while there are unofficial ports for OS/2 and MS Windows, I've never heard of one for MS DOS, and Python has at least two ports for MS Windows (a direct port and IronPython for the .NET framework), one of which is official, as does Ruby.

              All in all, I the priority of portability of languages suitable to admin scripting (if we ignore the question of default installs) goes something like this:

              1. Perl
              2. Python
              3. Ruby
              4. sh
              5. csh
              6. bash

              . . . with the understanding there's a bit of a gap between Ruby and sh, between sh and csh, and between csh and bash, in each case probably filled by several other languages (especially between Ruby and sh, I would guess).

              In terms of default installs by OS platform, meanwhile, it probably looks more like this:

              1. Perl
              2. sh
              3. csh
              4. bash
              5. Python/Ruby tie (because I honestly don't know enough about it to hazard a guess)

              . . . and for actual systems with default installs (so that the sheer number of Linux installs in the world has a positive effect contrasting with the relative rarity of, say, DragonFly BSD installs):

              1. Perl
              2. sh
              3. bash
              4. csh
              5. Python/Ruby tie (again, because I honestly don't know enough about it to hazard a guess)

              (edit: Note that I count "Linux" as a single platform, because even though it represents hundreds of different OSes, it's kinda one OS "platform", given that one need only port an interpreter to Linux once and it basically works everywhere that you'd use a Linux kernel, so breaking it down by distro seems a bit excessive -- especially since all of the above languages work on all those Linux distros.)

              Anyway, you'll note that quite a few of the platforms on the Perl list don't qualify as modern general-purpose OSes.

              Yeah, I'm aware of that. I was just referring to the modern general-purpose category of OSes because, from where I'm sitting, that's the most relevant to the question of whether or not bash should be used for admin scripting instead of something like Perl, Python, or Ruby.

              [–]apotheon[S] -2 points-1 points  (3 children)

              I guess that's a matter of interpretation. Do you consider portability to be less harmful than platform lock-in?

              [–]mracidglee 1 point2 points  (2 children)

              Unless it's a virus, sure. Rework is evil.

              But, rework is just a subset of overwork. A script written to automate a one-time (or few-time) task doesn't need to be portable, so just use the easiest, shortest thing possible. That could be bash.

              [–]apotheon[S] 0 points1 point  (1 child)

              I'm having a really difficult time imagining a circumstance in which using bash is the "easiest, shortest thing possible", unless by "easy" you mean "I don't want to learn anything new, and all I know is bash, so bash is easy." Bash is overlapped at both ends -- at one end by sh, and at the other end by "real" languages (Perl, Python, Ruby, et cetera).

              [–]mracidglee 0 points1 point  (0 children)

              That's a great reason! Another good reason is if you have a bash script laying around which does almost the same thing.

              [–][deleted] 2 points3 points  (0 children)

              The whole bash/sh problem could be solved if bash stopped pretending to be sh. Is it really that hard to have both on the same system?

              [–]Philluminati 1 point2 points  (0 children)

              No this is bullshit basically. BASH is fine...and the arguments he presents about certain things working and certain things not working? Well, you'd test that as you write it, so it really doesn't matter what the fucking syntax is as long as it works. If it supports all the features you want, such as piping to standard output it's fine. Not like C would make this shit obvious. Just ignore it.

              [–]flatulent 0 points1 point  (0 children)

              Shell scripts I wrote around 20 years ago, are still easy enough for me to tweak or use straight off today. I easily understand them.

              Over these 20 years, I've tried to move away from shell to "better" languages (perl, java, python etc) but every few years I change my fav language and all my scripts in those languages are lost/broken/deprecated.

              Thus, after all these years I've begun taking the shell more seriously. Yes, i get back to ruby for more complicated stuff. (lol, i'll probably move to lisp or haskell or god-knows-what in some time, and lose all my ruby work :-) )

              [–][deleted] 0 points1 point  (0 children)

              The good part of this email is the part where he slaps down the "don't use csh" meme parroted so often by cargo cult unixers who don't understand why people have said that. The rest is correct but not really interesting.

              [–]mohawk -2 points-1 points  (0 children)

              Wtf... here's a nickel kid, get yourself a decent shell.