6 ms·
Other tips I've found after a year or two of using Bash for many things it shouldn't be used for: - Use shellcheck (static analysis/linter) https://www.shellch
by exdsq 6y ago
Other tips I've found after a year or two of using Bash for many things it shouldn't be used for:
- Use shellcheck (static analysis/linter) https://www.shellcheck.net/ https://www.shellcheck.net/
- Use shunit2 (unit tests) https://github.com/kward/shunit2 https://github.com/kward/shunit2
- Use 'local' or 'readonly' to annotate your variables
- Trap ctrl+c to gracefully exit (details here https://www.tothenew.com/blog/foolproof-your-bash-script-some-best-practices/ https://www.tothenew.com/blog/foolproof-your-bash-script-som...)
- Stick to long-form options for readability (--delete over -d for example)
- #!/usr/bin/env > #!/bin/bash for portability
- Consider setting variable values in a file and importing it at the top of your script to improve refactoring
- You will eventually forget how your scripts work - seriously consider if Bash is your best option for anything that needs to last a while!
- mehrdadn 6y agoDo you want to trap INT, or EXIT?
- exdsq 6y agoEXIT is trapped in the same way as 0, it's something that happens when your shell exits. Ctrl+C sends the SIGINT signal but you can catch it with INT too. You want to do the latter because your gracefully exiting the script, if you want to have some cleanup after that you could trap EXIT (for deleting tmp files or something).
- jwilk 6y agoWriting good SIGINT handler is a bit tricky. You should re-raise the signal, so that bash notices that the program was actually interrupted: https://www.cons.org/cracauer/sigint.html https://www.cons.org/cracauer/sigint.html (section "How to be a proper program") Most of the time, especially for short lived script, adding signal handlers is not worth the trouble.
- asicsp 6y agoSome more useful links: * https://mywiki.wooledge.org/BashFAQ https://mywiki.wooledge.org/BashFAQ * https://mywiki.wooledge.org/BashGuide/Practices https://mywiki.wooledge.org/BashGuide/Practices * https://mywiki.wooledge.org/BashPitfalls https://mywiki.wooledge.org/BashPitfalls * https://devmanual.gentoo.org/tools-reference/bash/index.html https://devmanual.gentoo.org/tools-reference/bash/index.html
- hivacruz 6y agoI would also add shfmt, to format scripts: https://github.com/mvdan/sh https://github.com/mvdan/sh
- amarshall 6y agoNote that /bin/bash isn’t completely portable (though /bin/sh is, that’s not Bash) as some systems have it at /usr/local/bin/bash.
- m463 6y agoThat's what i've learned... #!/bin/sh is generally what I use and it survives porting. If I need more power I usually switch to python. (Probably not relevant to a bash discussion though, sorry)
- laumars 6y agoYou’re just reiterating the GPs point of using env instead of calling bash directly from the shebang: #!/usr/bin/env bash is more portable than #!/bin/bash Though personally if I was worried about portability then I’d just write the script in vanilla sh instead.
- spurgu 6y ago> using env instead If this method is superior, why hasn't it caught on with Bash I wonder (it's considered standard with Python and Node at least)? > Though personally if I was worried about portability then I’d just write the script in vanilla sh instead. Agreed.
- laumars 6y ago> If this method is superior, why hasn't it caught on with Bash I wonder (it's considered standard with Python and Node at least)? Because if you need a portable bash then you target sh. But if you want a portable Python then you still target Python.
- josefx 6y ago> But if you want a portable Python then you still target Python I am still supporting systems that came with Python 2. You get portable Python the same way you get portable bash: build and deploy the interpreter with your code.
- jancsika 6y ago> - Trap ctrl+c to gracefully exit (details here https://www.tothenew.com/blog/foolproof-your-bash-script-som https://www.tothenew.com/blog/foolproof-your-bash-script-som...) I'd rather that most devs don't touch that signal. Using that binding and having a GUI or CLI program continue hanging because the dev screwed up the cleanup is a real pain. And someone writing a Bash script is highly likely for doing something "very clever" with that signal to make my life harder. Or if you're going to do something with it, at least make it clear you're trolling me. Show me a text add that forces me to choose my favorite Korean boy band before I can exit, or something in that vein.
- exdsq 6y agoThat’s fair! But sometimes I want to have a hook that basically says “Are you sure?” to catch mistakes in the wrong terminal or something. One thing I wrote recently took several hours to run and it’d suck to accidentally close it because I type without looking.
- jmholla 6y agoIn that case, you could not catch CTRL-C in the cleanup.
- nemetroid 6y agoAgree that developers should be very careful about messing up Ctrl-C. However, as others have pointed out, it can make sense for long-running processes (especially in cases where there's an intermediate result that can be output instead of the final result). I think a good compromise is to only ever trap Ctrl-C once, so that a double Ctrl-C always successfully interrupts.
- corytheboyd 6y agoHuge +1 to using long form options in scrips, even if you’re the sole maintainer of the script. Also if you have a command that takes many flags, breaking them out onto new lines can help keep it readable
- gkfasdfasdf 6y agoThis is a great list. Also while reading about 'readonly' bash variables I ran across this amazing project which lets you call native functions from bash [0]. My mind is spinning from the possibilities... [0]: https://github.com/taviso/ctypes.sh https://github.com/taviso/ctypes.sh
- txutxu 6y ago> - #!/usr/bin/env > #!/bin/bash for portability Yes... but do not take that as a "cargo cult script shebang". If you're a sysadmin writing a script for a company with 2k linux servers, that has a policy of "we only use linux version Foo X"... and we do not use other bash in the system than /bin/bash (no bash compiled by hand, no multiple versions of bash, etc)... then portability via "env" does not make sense. If you have two laptops and a raspberry at home, with debian or arch, and you write a script for yourself... then portability via "env" does not make sense. And last but not least... using env is slower. See: strace -fc /bin/bash -c ':' Vs strace -fc /usr/bin/env bash -c ':' On my system, that's 92 syscalls and 3 errors, Vs 152 syscalls and 8 errors. Just to start procesing. Diferent levels of system bloat (environment, library paths, etc) can give different results than my example. And as others said... if you're not using GNU/bash syntax and the script is really simple, the best for portbility is to go with /bin/sh. strace -fc /bin/sh -c ':' On my system 41 syscalls and 1 error... (and less RAM, CPU and pagefaults). If you're not using associative arrays, array indexes, non POSIX builtin options, and other bash extensions... if the script is just to join a few commands and variables... it pays the effort to write it in simple sh, both, for portability and performance.
- rmrfrmrf 6y agoTwo things for me are: - Do I trust my code to run on a machine where /bin/bash doesn't work? - Do I trust my users to have their PATH configured correctly? IME a user misconfiguring ~/.bashrc is about seven million times more likely than some theoretical argument about "portability", or even the idea that running my code on some unspecified version of bash that a mac user accidentally downloaded while screwing up a Homebrew copy/paste command is preferable to using the factory default that everyone has.
- zvr 6y agoBut also: - Do I respect people who have set up their PATH correctly (to prefer, by example, a newer /usr/local/bin/bash or $HOME/bin/bash than the standard /bin/bash)
- l0b0 6y agoI'm working on a book about Bash scripting which is currently in the review phase, and it includes most of these. For graceful exit I recommend `trap cleanup EXIT` rather than specifically trapping SIGINT, mostly because the special exit signal is triggered no matter why the script is interrupted. I wouldn't normally recommend pulling out variables into a separate files until those variables are used by more than one script. I'd be interested in the rationale for why that helps refactoring.
- heavyset_go 6y agoHave a title I can look for after the book is released?
- l0b0 6y agoThe title isn't fixed, but it'll be the first Bash book from Newline (https://www.newline.co/ https://www.newline.co/).