6 ms·
your script is longer than a few hundred lines of code you need data structures beyond simple arrays you have a hard time working around quoting issues
by chubot 13y ago
your script is longer than a few hundred lines of code
you need data structures beyond simple arrays
you have a hard time working around quoting issues
you do a lot of string manipulation
you do not have much need for invoking other programs or pipe-lining them
you worry about performance
It's not a sign you shouldn't be using bash. It's a sign you shouldn't be using ONLY bash.
People who insist on rewriting an ENTIRE program in Python, Perl, or Ruby fail to understand the Unix philosophy (this is a real misunderstanding I've encountered in my work, not a straw man).
You can just write the complex part in another language, but keep the rest in bash. In other words, main() stays in bash. Python et. al. is used as just another process. bash is a language for coordinating processes.
You don't want a 2000 line bash script. But it can be worse to have a 5,000 line Python script that shells out to tons of other utilities, or awkwardly and verbosely reimplements 'xargs -P' or 'sed -i'. Often you can do the same job with 500 lines of bash and 500 lines of Python (or C), and that is the ideal solution.
Python and bash are pretty radically different languages, and they are not interchangeable (the advices "just rewrite in Python" seems to imply they are). You can use each one for the things they are good at.
- japhyr 13y agoI think I might have accidentally down voted you. That was helpful feedback for me.
- chubot 13y agoNo problem... the way I think about is that Python/Perl/Ruby are for data structures, logic and control flow; while shell is for configuration and data flow. As mentioned above, things that belong in shell, and NOT in Python: - file system paths (these are parameters to Python scripts, not hard coded) - port numbers - user names - other config values - concurrency -- you can get really far with xargs -P, and sometimes & - pipelines (try doing this in Python without shelling out; it's horrible) Things that belong in Python and NOT shell: - complex control flow (e.g. I rarely write loops in bash; never a nested loop) - data structures (bash has hash tables, but I never use them) - arithmetic - parsing and cleaning individual lines or fields of data Basically it's policy vs mechanism. They really are mutually exclusive, and work well together.
- rix0r 13y agoFile system paths may belong in the shell, but what about paths with spaces? To be honest, I trust myself more manipulating paths in a language like Python than to put all quotes in the correct places in Bash :(
- chubot 13y agoHere are the quoting rules I use: - Avoid paths with spaces :) - If you have to handle paths with spaces, use double quotes everywhere, e.g. "$pidfile". - Always use "$@". I've never found a reason to use $@ or $* unquoted. I also write unit tests (in shell) if there is something unusual I know I have to handle. That's it. I don't think it's hard at all, although you will certainly see scripts in the wild where the author was confused about quoting, and quoting hacks pile upon hacks. If you use a consistent style, it's very smiple. There is a learning curve like there is with any language, but it's totally worth it. Shell is an extremely powerful language, and saves you MANY lines of Python code. I would say Python is definitely the easiest language to learn, but bash is not harder than say JavaScript.
- onli 13y ago> If you have to handle paths with spaces, use double quotes everywhere, e.g. "$pidfile". I'd like to add: Always use double quotes around paths. Or is there something I'm missing here?
- claudius 13y ago$ ls -l "*" ls: cannot access *: No such file or directory Of course, you might want that exact behaviour, but sometimes you want e.g. all .table files in a path with a space. I believe $ ls -l "path with/lots of spaces/"* is the correct solution, but it seems silly. I'm not entirely sure why variable expansion works inside double quotes but wildcard expansion doesn’t.
- elwin 13y ago
- nikatwork 13y agoModularity is nice, but it's generally easier to debug a program in a single context. I work with some deployment systems that chain together small scripts in a bunch of different languages. They are a nightmare to troubleshoot. I'd much rather the spaghetti was all on one plate than follow it from table to table...
- chubot 13y agoIf the tools are coherently designed, it should be easier to debug, because you can just use -x to log the commands being run and paste them in to see what went wrong. It's debugging with a REPL. The biggest mistake I see people making is to hard code paths, ports, user names, configuration, etc. inside Python/Perl scripts. All that stuff belongs in shell. All the logic and control flow goes in the scripts. If it's factored this way, then you have a very natural way of testing the scripts with test parameters (i.e. not production parameters). I don't doubt that there are many multi language shell scripts that are spaghetti. Factoring into processes is definitely a skill that takes thought and effort, and I don't think anyone really teaches it or writes about it. The only books I can think of know of is The Art of Unix Programming by ESR and the Unix Programming Environment. But it's definitely made me way more productive once I started thinking like this. People say talk about the "Unix philosophy" for a reason. It's a real thing :) It's not an accident that Unix is wildly popular and has unprecedented longevity.
- deleted 13y ago[deleted]
- Toenex 13y agoI'm glad someone mentioned debugging. Typically Bash scripts evolve into programs and one of the first things I always notice is how much effort I'm having to put into debugging. Indeed, since I started working with [plumbum](http://plumbum.readthedocs.org/en/latest/ http://plumbum.readthedocs.org/en/latest/) I now typically reach for python in favour of bash even for small jobs.
- Too 13y agoYup, until someone can show me a bash editor that understands all the processes that are invoked and gives me at least context aware code completion, parameter documentation, "go to definition" and "find all references" I'd rather keep my code in a language where I can get those features.
- barrkel 13y agoThis is how I work. Whenever possible, when I have to write a utility in whatever language, I write it such that it can easily be integrated into shell pipelines. That makes it far easier to glue multiple tools written in different languages together.
- __david__ 13y ago> …awkwardly and verbosely reimplements 'xargs -P'… Verbose, and almost guaranteed to be more accurate. The thing about python/ruby/perl is that when you do things the programmatic way you get safety by default. You don't have to remember to 'find -0 | xargs -0' and thing aren't going to bite you in the butt when filenames have spaces in them. Yes, you can make all that work with shell (heaven knows I've done it), but it's more work and sadly isn't shell's default state.
- anon4 13y agoTo add, if you need/want to you can write python and perl inline in bash like so: python3 - <<'END' print('hello world') END The advantage is that you still have only one shell script to ship, which makes sense when the python code inside it is specific to that one script. Remember to use the <<'END' variant so variable expansion isn't done inside the heredoc. On the other hand, $ doesn't do anything in python and if you're feeling like it (please make sure everybody else is also feeling like it) you can use variable substitution there, in effect generating a python script and executing it.
- vacri 13y agoPlaying around with it, I see that using <<'END' does not expand $variables in the block, but <<END does expand them. My google-fu is failing me; what's happening here?
- anon4 13y agoIt's two different syntaxes. Like the difference between '$VAR' (no expansion, literal string) and "$VAR" (with expansion). See http://tldp.org/LDP/abs/html/quoting.html http://tldp.org/LDP/abs/html/quoting.html http://tldp.org/LDP/abs/html/here-docs.html http://tldp.org/LDP/abs/html/here-docs.html