Live data from Hacker News

Shell script best practices, from a decade of scripting things

sharats.me

101–110 of 500 posts

Re: Shell script best practices, from a decade of scripting things

#101
post #79

I agree with basically all of this. A few more: The order of commandline args shouldn't matter. Env vars are better at passing key/value inputs than commandline arguments are. Process-substitution can often be used to avoid intermediate files, e.g. `diff some-file temp; diff some-file temp` If you're making intermediate files, make a temp dir and `cd` into that - Delete temp dirs using an exit trap (more reliable tha…

> - It may be useful to copy `$PWD` into a variable before changing directory Why not use pushd/popd instead?

a) if pushd fails you are doing things not in the target directory, and when you call popd you are now in a totally wrong place. set -o errexit should handle this, but there could be situations (at least theoretically) when you disable it or didn't enable it in the first place

b) you need to mentally keep the stack in your head when you write the script. And anyone else who would be reading your script. (Edit: including yourself a couple of months/years later)

c) pushd $script_invocation_path is easier to understand and remember.

Eg:

    $global:MainScriptRoot = $PSScriptRoot
    $global:configPath     = Join-Path $PSScriptRoot config
    $global:dataPath       = Join-Path $PSScriptRoot data

    $dirsToProcess = gci -Path $PSScriptRoot -Directory | ? Name -Match '\d+-\w+' | Sort-Object Name
    foreach ($thisDir in $dirsToProcess) {
        foreach ($thisFile in $moduleFiles) {
            . $thisFile.FullName
        }
    }
It's PowerShell, but the same idea. I use it in a couple of scripts, which call other scripts.

Re: Shell script best practices, from a decade of scripting things

#102
post #18

What would be the justification for 'cd "$(dirname "$0")"'? Going to the scripts directory does not seem very helpful. If I don't care about the current directory, I might just go to '/' or a temporary directory, when I do care about it I better stay in it or interpreting relative command line arguments is going to get difficult. When symbolic links are involved, dirname will also give the wrong directory.

To be fair, it's common to want to be in the script directory for certain classes of scripts. For example, scripts which automate some tasks in a project, and are written for a project. But, more importantly, people will google for how to set cwd to the script directory more often then will google how to go to an absolute path. Having 'cd "$(dirname "$0")"' as reference in an article discussing best practices and the…

Those scripts are exactly the ones where I don't want to be in the script's directory. Something like this is more like what I use:

    project=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
ie, find the top of the git project, if there isn't one, use the current dir. My scripts live in ~/bin or similar and aren't where I want them to run.

Re: Shell script best practices, from a decade of scripting things

#103
One thing I try to do is retrieve information from the system instead of hardcoding it.

For example, instead of

    USER=mail
    UID=8
use

    USER=mail
    UID=$(id -u $USER)
It improves portability and removes potential sources of errors.

Also note that this is something that should be done in any programming language, not just shell scripts.

Re: Shell script best practices, from a decade of scripting things

#104
post #15

I favor POSIX and dash over bash, because POSIX is more portable. If a shell script needs any kind of functionality beyond POSIX, then that's a good time to upgrade to a higher-structure programming language. Here's my related list of shell script tactics: http://github.com/sixarm/unix-shell-script-tactics

POSIX sucks when shells aren't implementing it correctly. POSIX says that PS1 expansion needs to support at least the bang ('!') expansion and the regular parameter expansion ('$' and '${'), but i found that several kinds of almquist shells don't support that even when they are explicitly POSIX-compliant, dash included.

Bash in --posix mode does that perfectly.

Re: Shell script best practices, from a decade of scripting things

#105
There's a bug in his template.

He suggests to `set -eu`, which is a good idea, but then immediately does this:

    if [[ "$1" =~ ^-*h(elp)?$ ]]; ...
If the script is given no arguments, this will exit with an unbound variable error. Instead, you want something like this:

    if [[ "${1-}" =~ ^-*h(elp)?$ ]]; then

Re: Shell script best practices, from a decade of scripting things

#107

Use a linter. Pass all scripts through https://www.shellcheck.net/ or use `shellcheck` on the commandline. Learn the things it tells you and implement them in future scripts.

Thanks for the pointer! For some reason, I never looked for such a tool for shell scripts - and indeed, it pointed out a myriad of things in my code, most of which seem useful.

Re: Shell script best practices, from a decade of scripting things

#108
post #95

Do you guys think that Shell scripting will still be around in 20 years?

Why wouldn't it? While we've seen a trend towards consolidating systems infrastructure using more robust programming languages - as long as the shell is used for human-computer interaction (and I don't see this going anywhere), shell scripting will be around as a natural extension of the interaction. There is a beautiful ergonomics in conserving commands that you typed and interactively improved in a text file for future repeated execution.

Re: Shell script best practices, from a decade of scripting things

#110

Earlier quoted context omitted.

I don't know fish, but I don't consider zsh a step in the right direction, as it tries to be just a cleaned up Bash, which is not enough. There is a general problem in the fact that a radical evolution of glue languages wouldn't be popular because devs rather use Python, and small evolutions wouldn't be popular (ie. zsh), because they end up being confusing (since they're still close to Bash) and not bringing signifi…

zsh is, historically, a step from csh-like interactive shells in the direction of Bourne/ksh compatibility. It's easy to get the impression that zsh is a newer development than bash, but they're actually contemporary—bash rode on the popularity of GNU in the 90s, despite being a "small evolution" (frankly, a step back) compared to the ksh lineage.

It certainly didn’t hurt the popularity of Bash by having it be the default shell on tens of millions of Macs for so many years.

I’m aware that ZSH has been the default shell since Catalina.

Started using fish a month ago and really liking it.

Post reply on HN