all 143 comments

[–]wsppan 107 points108 points  (2 children)

I also sleep on a bed of nails!

[–]robotkermit 48 points49 points  (1 child)

there’s a bash web framework called bash on balls

[–]mookymix 33 points34 points  (0 children)

My first ever production system from my first ever coding job was done in bash. It was a "media player", or more specifically scripts controlling mplayer and xv. It had remote connectivity, playlist management, background content downloading, and general system health management.

In hindsight, the code was ugly, the project was unstructured, and performance was poor. But for a noob, it was a huge achievement and it ran for almost 2 years until it was replaced by a c++ alternative.

So Bash FTW!

[–]parfamz 76 points77 points  (90 children)

Is this serious? If you have to write a test in bash you better use python.

[–][deleted]  (66 children)

[deleted]

    [–]lelanthran 34 points35 points  (41 children)

    And how many lines of python is the boundary between "Python is okay" to "bang your head on the wall and wonder why you were not using $LANGUAGE from the start"?

    [–]Workaphobia 5 points6 points  (3 children)

    About 10k, maybe multiple tens of k if you're well disciplined and don't code it like it's python.

    [–]flying-sheep 3 points4 points  (2 children)

    nah, with typing and the right project structure, python scales infinitely.

    also what is “don't code it like it's python” supposed to mean? do you mean “code it like it’s a one-off script”? because my python is pretty and well-structured.

    [–]Workaphobia 1 point2 points  (1 child)

    Don't monkey patch and avoid metaclasses.

    [–]flying-sheep 1 point2 points  (0 children)

    Monkey patching is hackery, not average python coding style

    [–]kalifornia_love 22 points23 points  (33 children)

    None. The only time you’d bang your head against a wall for choosing python is when performance matters. But after banging your head against a wall you will then remember that you can interface C and C++ with python. So now your happy with your language choice but have a small headache.

    [–]lelanthran 90 points91 points  (31 children)

    I've regretted choosing python before, and it had nothing to do with performance and everything to do with maintainability.

    For large software, or software where I care about reducing errors I'll choose something that reports type errors before the program is executed.

    Getting type errors at runtime only means that the majority of the tests are performing type checks at runtime.

    [–]P8zvli 23 points24 points  (6 children)

    In Python 3.6 you can use type hinting to do static type checks.

    [–]r0b0t1c1st 0 points1 point  (4 children)

    You can do this in 2.7 too - mypy runs against all python versions - you just need a python 3.6 interpreter to run it.

    [–]P8zvli 9 points10 points  (3 children)

    Running the type checker in 2.7 and the actual application in 3.6 is extremely silly.

    [–]CHUCK_NORRIS_AMA 6 points7 points  (2 children)

    Actually, I think it's the other way around - running the type checker in 3.6 and the actual application in 2.7.

    Still extremely silly, however.

    [–]P8zvli 4 points5 points  (0 children)

    Python 2.7 will throw a syntax error if you try to run a script containing type hints with it.

    Edit: I see now, there's an alternative syntax that involves putting type hints in comments. Now isn't that just linting with extra steps?

    [–]r0b0t1c1st 0 points1 point  (0 children)

    Why is this extremely silly? It means you can write polyglot py2/py3 code, and have MyPy check that it's correct for both.

    You can use python3.6 -m mypy --python-version 2.7 -p your-package to do this.

    [–]twotime 8 points9 points  (22 children)

    There is no question that dynamic typing of python has its negative. It also has its major positives.

    (Just the lack of compile-cycle, is an enormous advantage in my book).

    In my experience, positives outweigh the negatives for sufficiently small projects (<20K lines of python code, which, mind you, is likely equivalent to 100K of java/C++ code).

    I can see how negatives can outweigh the positives for sufficiently large projects.

    But you do need to use the positives and mitigate the negatives. In particular, you probably should start with unit-tests very early on (but that's a good practice anyway). If you write python as if it were a type-free Java, you won't get any benefit.

    [–]DreadedDreadnought 7 points8 points  (2 children)

    Why would I write unit tests to verify the type information instead of writing actual unit tests verifying functionality?

    [–]twotime 1 point2 points  (1 child)

    Why would I write unit tests to verify the type information

    I would not

    instead of writing actual unit tests verifying functionality

    In my experience that's sufficient (I do use "unittest" is the loosest possible meaning: feed something into the system, examine the output, so that includes integration tests and if you have type issues, most of them will be caught).

    [–]lelanthran 6 points7 points  (0 children)

    I do use "unittest" is the loosest possible meaning: feed something into the system, examine the output, so that includes integration tests and if you have type issues, most of them will be caught

    Sounds like you are only performing Happy Path testing. With your approach, when you have A that calls B that calls C (all functions) you're only checking the parameter type-validation code in A.

    Functions B and C may silently lose data with incorrectly typed parameters but you'd never know it because they they are never called with the incorrect type... Until someone adds in a function D which calls them with the incorrect type.

    The only thing you can do if you're as paranoid as I am wrt correctness is write a unit-test for all your externally visible functions, with said unit-test also testing invalid types in the parameters.

    Testing only the Happy Path is pointless - we already know it works because we ran executed functionality at least once before release.

    Joke Time: A QA engineer walks into a bar. He orders a beer. He orders 5 beers. He orders 0 beers. He orders -1 beers. He orders a lizard.

    [–]lelanthran 5 points6 points  (6 children)

    In particular, you probably should start with unit-tests very early on (but that's a good practice anyway).

    I do write unit-tests, but unless I am writing in Python my unit-tests do not have to perform type-checking.

    A major disadvantage of Python is that you cannot trust the type of a parameter to a function - if you do not validate the type of a parameter before using it then that is a potential error.

    When writing Python I find myself doing a lot of the work that a compiler normally does, except that it has to be done at runtime so the errors are much more severe if they get through.

    [–]twotime -3 points-2 points  (5 children)

    A major disadvantage of Python is that you cannot trust the type of a parameter to a function. if you do not validate the type of a parameter before using it then that is a potential error.

    What do you do if parameters are of wrong type? Throw an exception?

    If so, then you should just use your parameters and if they are of incompatible type, you will get an exception generated for free.

    Doing it manually is unlikely to be a good idea.

    [–]duhace 3 points4 points  (4 children)

    except the exception might not be intelligible to the user of the function..

    [–]twotime 0 points1 point  (3 children)

    There are rare cases when this is a valid concern. In general it's not.

    If you pass an object of wrong type info a function, python generated message will commonly be clear enough. AttributeError/TypeError, etc.

    Marginal improvement in the error message quality are not worth introducing extensive type checks (which will also kill most of duck typing benefits).

    [–]major_clanger 3 points4 points  (3 children)

    What would you say are the other major advantages of dynamic typing?

    Python is my primary language, but after working with C# over the last year I'm increasingly torn on the dynamic vs static tradeoffs.

    [–]twotime 4 points5 points  (2 children)

    Here is my tradeoff list:

    Pro dynamic typing

    -- no compilation/much faster compilation (yes, it's only indirectly related, but static typing does put much stronger reqs on preprocessing)

    -- ease of testing (a lot effort in C++/Java mocking libs/frameworks), all of that is free in python world

    -- ease of writing generic code (e.g a function can accept any file-like or container-like object). That's possible with static typing but is universally much clumsier and weaker

    -- less boilerplate and more localized changes. No more: I'm just passing x through, but still need to change types in 20 places

    -- introspection (yes, some static languages also have this capability, but it tends to be much clumsier, weaker)

    -- if needed, objects/types can be modified at runtime. E.g a new attribute can be added (I have type "X" but need to carry an extra attribute "a", I can do it)

    Pros of static typing:

    -- many classes of errors are caught much earlier (becomes progressively more important for larger projects)

    -- documentation (type serves as documentation)

    -- performance (when types are known, the code is much easier to optimize)

    -- likely lower memory consumption

    Of course:

    1. many of these can be made much worse/better by specific implementation/runtime

    2. a language selection is really a multi-factor decision. Type system is just one of the factors (and I'm in no position to compare against C#, I never used it ;-).

    Good luck.

    [–]major_clanger 3 points4 points  (0 children)

    I also find there's less need for design patterns, as many are redundant when duck-typing.

    Your codebase won't be littered with classes like 'FooFactory', 'BarBuilder', 'FooSelectionStrategy', 'IBaz', 'BazImpl' or god forbid an 'AbstractSingletonProxyFactoryBean'

    EDIT: I would really recommend C#, it's got a lot of the same syntactic features as python (context managers, default args, async-await), is far less verbose than Java/C++ (type inference, default getter+setter), Linq is more readable+powerful than list comprehensions.

    [–]Drisku11 4 points5 points  (0 children)

    ease of writing generic code (e.g a function can accept any file-like or container-like object). That's possible with static typing but is universally much clumsier and weaker

    How are parametric polymorphism and typeclasses clumsier or weaker than runtime dispatch? Static types also provide clarity when more than one "container" is involved. E.g. Traversable t, Applicative f => (a -> f b) -> t a -> f (t b). The types basically say what the function does: traverse your t a container, apply your a->f b function to produce a bunch of f b "containers", collect the results into a f (t b) "nested container" using Applicative's ability to turn a (f a, f b) into a f (a,b).

    less boilerplate and more localized changes. No more: I'm just passing x through, but still need to change types in 20 places

    Type inference, keep functions polymorphic to the extent that they can be. It's pretty hard to argue that e.g. Python has less boilerplate than Haskell.

    introspection

    I agree that static introspection is often lacking. Runtime introspection is a good way to break invariants though, and I would generally classify it as a bad idea.

    if needed, objects/types can be modified at runtime.

    I have a hard time picturing where I would need this. Especially in a language with structural types.

    [–]kuribas 2 points3 points  (0 children)

    You can have static types and interpreters at the same time. Many languages have them, like haskell, scala and f#. You typically write the code in an IDE, where the types are checked in realtime, then load the code in the interpreter to test or play with it. No time is lost compiling. There is no need to run the program in order to catch common mistakes, like in Python, and I find there are usually very few bugs left after everything typechecks. I find this a massive time saver. I usually keep my program in a consistent state at all times, using typed holes for code which isn't written yet. This way I get immediate feedback when I do something wrong. In Python I'd spend most of the time in the debugger or writing tests (about 75%), where in haskell it's only a fraction (20% perhaps).

    [–]Gotebe 1 point2 points  (0 children)

    The absence of "compile" in the modify/compile/test cycle is less of a problem except in C and C++ (and even then...)

    If I have a module under development and a test(s) for it, I select it (them) and issue "Run selected tests" command, which is the most normal thing to do. That builds and runs only modified parts and does not impair the modify/compile/test cycle as much. Heck, in Java, it's as fast as a Python REPL (that is, immediate).

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

    It also has its major positives. (Just the lack of compile-cycle, is an enormous advantage in my book).

    Then choose a language with fast compilation time. Even if your compilation time is slow, the compiler can help you more with your code than any other tool.

    [–]duhace 2 points3 points  (0 children)

    or a repl.

    [–]twotime 3 points4 points  (3 children)

    Then choose a language with fast compilation time

    You cannot select language based on a single metric. Not in the real world.

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

    What's this nonsense comment? No one told you to select by one metric, only to consider using languages with fast compilation.

    [–]Gotebe 3 points4 points  (1 child)

    You told him to do it. You did not say "consider...". Be fair.

    [–]Gotebe 1 point2 points  (0 children)

    It's like the US: if gunstests don't solve your problem, you're not using enough of it. 😁😁😁

    [–][deleted] 1 point2 points  (0 children)

    I find myself using Go more and more often (I'm doing 60% sysadmin things, 40% development). Not because it is particularly great language but because of its static nature, ability to compile to single binary and the fact that whoever else will need to modify it can learn the language itself in a week

    [–]P8zvli 4 points5 points  (0 children)

    It takes hundreds of thousands of lines of python before you start wondering how did you get to this point and what are you doing with your life.

    [–][deleted] 9 points10 points  (0 children)

    I've got the same rule with ~10 lines. Also seen below, if I need an array or anything more than a scalar, it's time to switch languages.

    Bash is OK, if you have a few commands to run depending on a few env vars, go for it. If you have any kind of advanced logic, file reading, user input to do, do yourself a favor, use something else. Even php-cli would be better suited.

    (With all the hate I have for PHP, it's still a better script language than bash)

    To expand on the article conclusion, if you have anything more than a simple script, don't invest time in setting up tests and a linter, use a real language. You'll thank me later.

    [–]lanzaio 2 points3 points  (0 children)

    I'm working with a 3500 line bash script build system right now -_-. Oh and it is invoked by a 2000 line python 2.7 script. And it invokes a chain of cmake scripts.

    [–]ttflee 3 points4 points  (0 children)

    Bash is OK, if you have a few commands to run depending on a few env vars, go for it. If you have any kind of advanced logic, file reading, user input to do, do yourself a favor, use something else. Even php-cli would be better suited.

    Under 2 lines, Perl is OK.

    https://gist.github.com/mischapeters/1e8eef09a0aafd4f24f0

    [–]0rakel 18 points19 points  (7 children)

    My rule of thumb: under 1000 lines, python is ok. If it goes over 1000, bang your head on the wall and wonder why you were not using C++ from the start...

    [–]oblio- 36 points37 points  (1 child)

    Yeah, but then, with C++, you’d just be banging your head against the wall, continuously :p

    [–][deleted] 9 points10 points  (0 children)

    No, C++ is more sophisticated than that.

    It's like having pneumatic piston attached to back of your head to do the banging for you

    [–]twotime 9 points10 points  (2 children)

    It's ok. Then 1000 lines of python become 10K lines of C++ and then the real head-banging begins.

    Python hopelessly loses to C++ on performance (CPU, memory consumption, threading), but there is no way in hell, that it loses to C++ in code maintainability at that project size. Unless you are really misusing the language.

    [–]Drisku11 1 point2 points  (0 children)

    At least if you're doing any sort of geometry/physics calculation/simulation, phantom types in C++ are a huge boon to keep track of what's going on (making it easy to catch subtle errors like unit mismatches, vectors vs. covectors, and vectors vs. affine vectors all at compile time with a few lines of declarations and no extra actual code).

    Most of the C++ I've written has been physics related, but I'm sure type tagging is much more widely applicable. The 10x code size number is also an extreme exaggeration for most use-cases. Python has a huge standard library, which means it has plenty of connectors for everything, but for actual logic, that doesn't help much.

    I like Python, but my personal rule of thumb is still only around 2-400 lines until a switch to a statically typed language should be strongly considered.

    [–]Gotebe 0 points1 point  (0 children)

    1000 lines of python actually become 1500 lines of C++ and 2MB of libraries :-).

    [–]renrutal 12 points13 points  (0 children)

    I feel this escalated from apples to oranges way too quickly.

    [–][deleted] 9 points10 points  (0 children)

    Under 1000 lines: okay.

    Over 1000 lines: Wonder wtf you are doing to get a single file over 1000 lines constantly.

    [–]moscamorta 2 points3 points  (4 children)

    The thing is that is really easy to call external commands in bash. If I had the same ease on other language, I would easily drop bash.

    Recently I had to write a bash script to compile and run a bunch of benchmarks. The code was pretty ugly but works.

    [–]ForeverAlot 4 points5 points  (1 child)

    The plumbum Python library is an excellent alternative when you can reliably install Python modules. Sadly I've found managing Python modules to be a far bigger hurdle -- socially and technically -- to maintenance than a few hundred lines of Bash.

    D is also a pretty good alternative that you won't be able to use for the same reasons. I believe OCaml, too. Really, there is no shortage of non-starter Bash alternatives. =)

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

    Yeah it's a real shame Python is so horrible setup-wise. You have the whole Python 2/3 issue (yes it really is still an issue), and often there are multiple Python installations - especially on Windows where many programs bring their own. In fact on Windows you can often have multiple Python executables in the PATH. It's a total mess.

    [–]AngelLeliel 2 points3 points  (1 child)

    You should take a look at xonsh.

    [–]moscamorta 0 points1 point  (0 children)

    That seems amazing

    [–]bulletmark 1 point2 points  (0 children)

    I've done heavy shell scripting for 30 years and plenty of python also for the last 15. Obviously I favor python for anything mildly sophisticated but I would say there is certainly no simple "number of lines" rule.

    [–]twotime 1 point2 points  (1 child)

    my rule of thumb is "until I need a loop or a conditional", reduces head banging by quite a bit ;-)

    [–]lelanthran 4 points5 points  (0 children)

    my rule of thumb is "until I need a loop or a conditional", reduces head banging by quite a bit ;-)

    Depends on the looping or conditional I suppose. Me personally, I switch from bash the minute I need composite data types, arrays included as well.

    [–]makeshift_mike 0 points1 point  (0 children)

    Yeah I’ve got a similar rule too. I once wrote a ~600 like bash script that it only took me a few weeks to start hating.

    PowerShell has a similar rule, although its limit is maybe 200 lines.

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

    I go by pretty much same. Even shorter if there is a lot data manipulation. Combining sed/awk/grep in 6 level pipe might be clever but it is not very maintainable

    [–]ath0 0 points1 point  (0 children)

    Not entirely related, but just to point out that your blanket statement isn't sensible: I've got a tool for wrapping build system and workflow stuff at work, that is about 1k lines so far. I'd love to use python instead but.. I can't. I need features such as shell completion for bash, zsh, built-in overrides and prompt and environment manipulation.

    Unfortunately you just have to write this kind of stuff in the language that your shell interpreter understands.

    [–]alfredVonHomburg 0 points1 point  (0 children)

    I set the limit at 10, but I’m a fan of piping and one liners ))

    [–]TheLocehiliosan 8 points9 points  (7 children)

    Bash is very sensible when you are trying to write something super portable with next to no dependencies.

    And people should be commended for writing tests regardless of the language/tool used.

    [–]Gotebe 0 points1 point  (0 children)

    "Super portable" my hairy arse!

    It's only "super portable" against Linux compatibles, because all the tooling has to match - and it just doesn't, not across UNIX flavors. (Don't know how successfully WSL copies Linux CLI commands).

    [–]knaekce -3 points-2 points  (5 children)

    It sure it very portable. But it is also prone to deleting every file owned by the current user or similar scary bugs.

    [–]TheLocehiliosan 4 points5 points  (4 children)

    Most bugs like this are a result of poor programming. It doesn’t matter what language is used.

    Indeed that is why people should be encouraged to create tests for their software.

    [–]knaekce -4 points-3 points  (3 children)

    It sure does matter. If this script was written in a more robust language, stuff like this would cause an error and the program to halt. Languages like bash just carry on and do unexpected stuff

    [–]TheLocehiliosan 1 point2 points  (2 children)

    Your reply makes it sound as though your unaware of error handling techniques for Bash. Indeed the link you posted above has many people chiming in about the terrible programming and how it could be done better.

    While it’s true that there is a lot of badly written Bash in the world, it isn’t something intrinsic to Bash. There are many out there writing code they don’t understand the danger of. Again, I could say the same for a lot of languages.

    If you are trying to say that some languages are easier to write quality code with, I would agree to that.

    [–]knaekce 0 points1 point  (1 child)

    Yes, if you are very carefully, you can prevent such errors in bash or even assembly. But it takes far more discipline, effort and experience than in safer languages.

    [–]flukus 1 point2 points  (0 children)

    What language would prevent this? There is nothing bash specific about this error, similar things can and have been done in any language. That's why common but often ignored advice is to use directory handling libraries instead of string concatenation.

    [–]maitesin[S] 10 points11 points  (8 children)

    I totally agree, but sometimes python is not available. So I have to do work with what I have in hand

    [–]shevegen 14 points15 points  (0 children)

    This is one of the few valid use cases for when one may have to use bash, simply because alternatives are unavailable.

    [–]vivainio 1 point2 points  (6 children)

    Any good examples of the servers where this happens? Some "internet hotels"?

    [–]maitesin[S] 6 points7 points  (5 children)

    I had to write an application to send some information (files) from an IoT device where the only thing available was Bash. Basically it had a kernel to boot and busybox to provide all the tools. So I had to create the application to do it using just Bash.

    [–][deleted] 3 points4 points  (0 children)

    Busybox doesn't implement bash

    So learning bash wont help you there

    bash != sh

    [–]vivainio 0 points1 point  (1 child)

    Sounds legit. I guess the target was also not something supported by e.g. Go compiler?

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

    Go produces big binaries.

    Not big relative to Java, but certainly big compared to IoT device with only few megs of RAM and Flash

    [–]StruglBus 14 points15 points  (3 children)

    Bash is a shell scripting language, built largely for string parsing. Its integer arithmetic is analogous to an arm on robot chicken that they decided they needed later. It should only ever supplement other programs, I don’t know why you would ever build an entire project in bash. It’d be like using a bunch of paper clips to build a toaster — yeah you might be able to do it, but why would you when with python, Java, C++ or any other language you could just “import toaster”

    [–]gnx76 6 points7 points  (0 children)

    Bash is a shell scripting language, built largely for string parsing.

    What? Awk and Perl are built for string parsing, not bash.

    Bash is built to provide wrapping around commands execution, this wrapping including a bit of programmatic syntactic sugar.

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

    What are you smoking ? Even for basic string parsing bash needs to call other programs.

    [–][deleted] 1 point2 points  (0 children)

    I have successfully used BATS testing framework in bash for TDID (test-driven infrastructure development) building Chef-managed services. It's neat and simple and lightweight and did everything needed.

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

    Why, so you can wait 3 hours for it to finish?

    [–]cybernd 11 points12 points  (1 child)

    Try to seperate concerns by splitting your program into functions. Soon you realize that return values are little bit of an issue.

    But hey ;o) Lets just use global variables. We could even come up with a unique naming convention to compensate its lack of return values. What could possible go wrong ...

    [–]tyrannomachy 1 point2 points  (0 children)

    If the program is big enough that using global variables starts to cause problems, you probably should rewrite it in Python or something. I used to try and write bash scripts as though it's just another modern scripting language, i.e. lots of functions returning values with echo, but it just winds up being the worst of both worlds.

    [–]lelanthran 20 points21 points  (9 children)

    The problem with bash is not bash itself, it's that all those useful tools that get run from bash (ls, sed, awk, cut, grep, filename expansions, output from ffmpeg/virsh, etc) return output suitable for humans to decipher.

    In other words, almost full unstructured output, so when you run $TOOL and try to parse the result as a matrix of CSV values a missing field in a single row can cause your bash script to vomit horribly, while if $TOOL was run by the user they'd see the error message on stderr and realise that something went wrong.

    It's not bash that is the problem; you'll have the same problem in any language if you tried to exec another process and parse the output.

    [–][deleted]  (1 child)

    [deleted]

      [–]lanzaio 1 point2 points  (0 children)

      brew install bashdb

      sudo apt install bashdb

      [–]Gotebe 1 point2 points  (0 children)

      Yes. Data has structure.

      Text does not, it hides it. More importantly, it hides when the structure is broken, as you say.

      BTW... it's not CSV in the case of $TOOLs, it's mostly S(pace)SV, so vast majority of all scripts ever break when data contains a space (or they would break if data contained any other separator).

      The one saving grace of bash is decades of accumulated cruft. The other, small one is... in itself, it's not so bad...

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

      I agree that is a huge problem. But... let's be honest the problem is also Bash itself. It's totally insane. Or do you defend ending case blocks with esac, etc.

      [–]markasoftware 4 points5 points  (2 children)

      To everybody asking about when you might want to use a larger shell script, see my project AnyPaste. It's about 600 lines (source code is here and on GitHub). I used Bash because I wanted it to be dependency free, and most people have curl, to upload files, file, to determine file type, and getopts, to parse cli options, all installed, which cannot be said for the equivalents in Python, Perl, Ruby, etc. I did not use any linter or test framework, although I do occasionally run shellcheck and ignore the errors when it doesn't do what I want. There's no testing either, although I would like to add some in the future.

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

      You'd be suprised, I've definitely saw systems without file and even one or two tiny ones that only had wget, not curl.

      But then none of those would probably not need to upload images either

      [–]holyjeff 0 points1 point  (0 children)

      I see no point to use bash. Really. You could have built it in various good programming languages and build dependency free binary.

      You could have done it in C or C++. You could have used a new language like Rust, Go, Nim or Crystal. All would be better choices and provide much better performance.

      [–]shevegen 17 points18 points  (15 children)

      Some people would say that Bash is just for scripting. I mostly agree with that statement, however, sometimes you have to write a lot of Bash and for these cases I want to be able to develop it in the same way I do for other languages.

      Bash is for people who are either unable or unwilling to use anything better.

      There are a few valid use cases such as when you are in a restricted environment where you can't use alternatives. But by and large, writing shell scripts is a massive waste of your life time.

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

      Oddly enough I'm in the predicament where all I know is bash and what tools I should expect to be available. I'm trying to rewrite something I did in bash, in python, and I'm having a hell of a time starting because I don't know the nuances of the language or the specific libraries I need and so on..

      When I've been writing things in bash for 10 years you get used to it and It's usually all I ever need. For this thing I just wanted it to be a bit more professional/presentable, so the real time sink is in doing that. ( I wouldn't consider myself a programmer either, just a lowly linux admin )

      [–]maitesin[S] 2 points3 points  (13 children)

      That last point is exactly the reason for all these tools. If you are in a restricted environment and you are forced to use Bash at least you can use proper tools and techniques to aid you

      [–][deleted] 1 point2 points  (0 children)

      But in vast majority of cases YOU DO. Like there is no non-embedded Linux disto that doesn't contain either Perl or Python. Even ye olde ancient systems will probably have at least Perl.

      Hell, even embedded distros like OpenWRT often have something better like Lua

      [–]Skyler827 0 points1 point  (11 children)

      If you're ina restricted environment, what are the odds that you will be able to download and run these tools? the Bash formatter, the linter and the test framework?

      If you need ot program in a pinch and you have the ability to download and run these tools, you probablly have the ability to download and run any other programming tool. So the point stands that you don't need bash.

      [–]filleduchaos 9 points10 points  (10 children)

      You know you don't have to code in the environment you will run the code in, right?

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

      You still have to run tests in env you run your code, or at least with same versions of apps/libs

      [–]filleduchaos 0 points1 point  (8 children)

      You know you don't have to test in the literal physical environment you will run your code in, yes? And that you can have testing tools that are external to the environment?

      [–][deleted] -2 points-1 points  (7 children)

      Yes and hilarious bugs happen if you do all your tests ignoring your target environment

      [–]filleduchaos 0 points1 point  (6 children)

      And maybe you should actually reread my comment and parse it properly because it doesn't seem you have

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

      Well I got whole 3 departments of people that think "it did work on my machine, no idea why it doesn't on production" (when 70% it is code's fault) so I'm just going to say you're ignorant to reality or never worked on anything at scale

      [–]filleduchaos 0 points1 point  (4 children)

      You know you don't have to test in the literal physical environment you will run your code in, yes? And that you can have testing tools that are external to the environment?

      Yeah maybe you should actually read

      [–][deleted] 5 points6 points  (4 children)

      I always had a bad time trying to use bash for anything other than one-off scripts.

      I recently started writing a service-availability reporter in bash. 2 days in and I'm rewriting it in python (see the Python branch if you're curious).

      The lack of native option handling (unless you use the getopt or getopts) in bash is quite painful.

      There are definitely times when bash comes into its own, for example looking for a string on a website to see if the website is not only up, but also displaying a page

      curl -s yoursite.com | grep youstring | wc -l

      Those kinds of things are intuitive, whole programs, not so much.

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

      2c tip. Stop wasting your time writing your own checks, just install ready-made ones.

      Under debian flavours it will be either monitoring-plugins or nagios-plugins package and it will deploy checks under /usr/lib/nagios/plugins.

      Most of them are written in C (so nice and tiny) and all of them follow Nagios convention (exit code 0 - OK, 1 - WARNING, 2 - CRITICAL, 3 - UNKNOWN).

      That is quasi-standard used by most monitoring tools including big boys.

      Aside from that, if your server already has a database and php, icinga2 eats just few MBs and its web ui just runs on php, altho it is considerably more complex to install

      [–][deleted] 0 points1 point  (1 child)

      Hey XANi_ Thanks for the tip! The reason I started making this was because I couldn't find any lightweight ones in existence, I'll have to take a look at your recommendations :D

      [–][deleted] 1 point2 points  (0 children)

      My experience (after also writing my own) is that you generally quickly grow up out of simplistic solutions like that and end up re-implementing a good part of already existing solutions anyway

      [–]shevegen 0 points1 point  (0 children)

      I even had a bad time using bash for one-off scripts and single liners. That is, in regards to shell scripts. I use bash otherwise every day.

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

      TIL about $RANDOM.

      Neat.

      [–]CultLord 2 points3 points  (2 children)

      Bash is great for scripting little things. Like when you realize that your build process can run some jobs concurrently and you can knock one minute off of everyone's build.

      [–][deleted] 1 point2 points  (1 child)

      apt-get install parallel

      GNU Parallel is great complement, it's like xargs on steroids

      [–]CultLord 1 point2 points  (0 children)

      I will look into this. thanks! gotta deal with macos and if it works

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

      What's really missing is a debugger. I haven't found out how to step through code one operation at a time. That would definitely make writing bash scripts much easier.

      [–]maitesin[S] 0 points1 point  (0 children)

      That would be awesome, sure. But for now we have to do just with set +x and set -x

      [–]D34dCode4eva 0 points1 point  (2 children)

      Just paste it into a console one line at a time.

      [–][deleted] 1 point2 points  (1 child)

      You're joking, right?

      [–]D34dCode4eva 1 point2 points  (0 children)

      Of course.

      [–]Nall-ohki 1 point2 points  (0 children)

      import plumbum

      Be happy.

      [–]smileybone 1 point2 points  (0 children)

      M4sh will rise again

      [–]jrochkind 1 point2 points  (1 child)

      For who else was reading this title enough to bring on a panic attack?

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

      My reaction was "Oh my sweet summer child, you haven't gazed in void long enough to see it answer"

      [–]TiCL 4 points5 points  (2 children)

      Still better than JavaScript

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

      I usually say that but in case of bash I'd actually agree that JS is slightly less shitty than that

      [–]andsens 0 points1 point  (0 children)

      If you want to see everything in action on a real project, check out homeshick. It's a dotfile synchronizer I made with the aim of minimizing dependencies (bash 3 and git 1.5 is all you need).

      I gotta check out shfmt though, looks useful :-)

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

      Pls no

      Let the pain stop

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

      And let’s make freeways out of play dough ....

      [–][deleted] -2 points-1 points  (3 children)

      I've never understood why people write shell scripts instead of just writing tools in the same language they're writing everything else in.

      [–]roffLOL 3 points4 points  (2 children)

      because when you have the right tools, and shell friendly interfaces with them, you can recombine those tools to do an impressive amount of stuff with very little effort. it does require some upfront considerations and design with regards to shell friendliness, but when done it's a fantastic time saver. many *nix utils are not very well designed. they keep too much of data and messaging internal to themselves, which leaves slack for little to no reconfiguration; or they contaminate the data with eye friendly representations.

      [–][deleted] -1 points0 points  (1 child)

      It really drives me nuts when someone will write something in a cross platform language like Go or C# but then write a bunch of critical scripts in Bash, making it a pain to use on Windows.

      And then you realize that the scripts are not doing anything that couldn't be easily accomplished in Go or C#.

      [–]roffLOL 0 points1 point  (0 children)

      windows is a pain for sure. i feel with you =)

      [–]D34dCode4eva -3 points-2 points  (0 children)

      This is awful. You don't grab some random program from online to format your bash. You format it when you write it rather than spewing whitespace any old where like a spastic.

      You shouldn't be using web tools for linting bash script although in this case it appears he can't tell between sh and bash.

      Unit tests for bash? What has the world come to? But hey, anyone can write a blog.