Live data from Hacker News

How to write idempotent Bash scripts

arslan.io

171–180 of 195 posts

Re: How to write idempotent Bash scripts

#171

Another tricky thing: recursively copying a folder is not easy to get right in an idempotent way due to arcane bash behaviors: https://unix.stackexchange.com/questions/228597/how-to-copy-...

That is hardly arcane, the context dependent behaviour of cp and mv is a well-known standard. You are right it does make making a copy in a given path more complicated task.

Re: How to write idempotent Bash scripts

#172
post #81
post #43

Earlier quoted context omitted.

https://linux.die.net/man/1/flock would probably help

flock(1) is not POSIX, though. mkdir(1) can be used if you absolutely want a POSIX way to manage locks. For example: if ! mkdir .lock; then printf >&2 "Already running?\\n" exit 1 fi Some network file system implementation do not guarantee atomic mkdir, so you still need an extra caution with this method.

Existence of a file is an unreliable indicator of script instance running. Much more reliable is to search the script name or other characteristic in the list of running processes. To use this, the script has to have unique name though.

Re: How to write idempotent Bash scripts

#173
post #2

The problem with the idempotent trend in configuration management is that it’s all based on not tracking or knowing what the current state of something is. So reasoning about how these systems work is fundamentally impossible. It would be better to focus on systems where by we can always know the state and improve the tooling there.

On the contrary. With idempotence you know the state after an action. rm -f will always delete the file (if possible). ln -sfn will always work, even for a directory. With the default behaviour of rm, ln -s, etc you know neither the state before, nor after.

The option -f is making the script more heavy handed and less likely to fail. But this is not necessary for the script to be idempotent and sometimes is not desirable. You can deal with errors in a more safer way and still be idempotent.

Re: How to write idempotent Bash scripts

#174
I like to use stuff like

mountpoint -q $MOUNTPOINT || mount ...

Instead of

if ! mountpoint -q $MOUNTPOINT; then mount ... fi

It's much more compact in the case of having a lot of commands that need to be checked in case they don't need to be run again.

Re: How to write idempotent Bash scripts

#175

Earlier quoted context omitted.

> An easy way to cover that is to have the script create a file, which you check at the start of the script and if present you exit. This does sound a good solution on paper, but "checking at the start" and "creating a file" are two different steps (i.e. not atomic) and will cause trouble eventually if your system has the tendency to run the script twice. A better solution is to use the `flock` command before creatin…

Within a shell script context, 'mktemp' and 'mv' are almost always what you want, possibly 'ln -s' for libraries. The first safely creates a temporary file. The second (with noclobber set or -n argument) will atomically rename a file, but not overwrite existing contents. Linux uses symlinks to system library files in order to allow in-place atomic replavement without affecting running processes with open filehandles…

>Linux uses symlinks to system library files in order to allow in-place atomic replavement without affecting running processes with open filehandles to earlier versions

Nope. If you rm a library, the processes using that library keep using the old library. Symlinks have nothing to do with it.

Re: How to write idempotent Bash scripts

#176
post #137
post #44

Earlier quoted context omitted.

Yeah, and tools like Chef are 99% blocked on disk operations anyways, so I have no idea why GP thinks Rust would help

CM systems spend a lot of time on bootstrapping, creating their workspace, downloading the scripts, parsing them, etc. Then they simply execute other programs to then parse their output. And/or fiddle with files (parse them, alter them, write them). Sure fundamentally the syscalls and apt/dnf/yum will be the slow parts, but I found that development of CM scripts/plays/recipes are usually bottlenecked on the turnaroun…

Why do we care about speed here? Surely reliability and readability are paramount features...

Re: How to write idempotent Bash scripts

#177

I like to use stuff like mountpoint -q $MOUNTPOINT || mount ... Instead of if ! mountpoint -q $MOUNTPOINT; then mount ... fi It's much more compact in the case of having a lot of commands that need to be checked in case they don't need to be run again.

I was going to mention this, but frankly it is just a style preference. No real difference between either variant. Also, you can do something like:

    mountpoint -q /proc || {
        mount -t proc none /proc
        chown 0400 /proc/slabinfo
    }
if you need multiple statements.

Re: How to write idempotent Bash scripts

#178
post #167
post #65

Earlier quoted context omitted.

The -n flag keeps echo from emitting a line ending.

I used a distro in recent memory where `echo -n foo` really produced `-n foo`. The workaround was `printf "%s" foo`.

Ah yeah, posix doesn't require -n to do anything in particular. For most use cases, strict adherence to posix compatibility isn't important, but sometimes it really really is.

Re: How to write idempotent Bash scripts

#179
post #149

Earlier quoted context omitted.

Well, sadly mktemp is not part of POSIX. So while it is available on a wide range of systems, there are also different implementations with different options. So while I like the job it does, I am also pretty disappointed how 'unportable' scripts become as soon as they use mktemp :-/

You can invoke mktemp(1) in ways that work across most contemporary systems. At least if you don't care that the resulting names are going to look a bit weird (have lots of XXXXXX in them due to name prefix vs. template differences among implementations).

Actually, I am not sure if that is true. I have no example at hand (I could look it up, if you are interested), but a few months ago I was trying hard to create a folder with mktemp using the same command for Linux, MacOS and Android, and as far as I remember, that wasn't as easy as it is supposed to be.

Re: How to write idempotent Bash scripts

#180

Earlier quoted context omitted.

Well, sadly mktemp is not part of POSIX. So while it is available on a wide range of systems, there are also different implementations with different options. So while I like the job it does, I am also pretty disappointed how 'unportable' scripts become as soon as they use mktemp :-/

It is sad to read these comments by people believing POSIX is something relevant today. My advice is to give up on false hope that POSIX will solve portability problems. POSIX ideas of shell are 30 years old and refusing to use anything newer alone won't make your script work correctly on all systems. If feasible, install bash, which has become the standard de facto . Or just write your script to test for the shell v…

I know that POSIX doesn't meet the expectations many of us have, but I don't see how it isn't relevant anymore? I mean, if you want to write portable shell scripts it is still a good reference on what you can expect to find on many systems (and which are options introduce by GNU and the likes).

Yes, ultimately you have to test your scripts on the actual systems, but that is something you have to do anyway. For example, when you run scripts on MacOS and you run into old Bash bugs because Apple refuses to ship an up-to-date version, those are issues a standard can't solve.

However, I have no experience how much you can count on POSIX when it comes to C APIs and the like.

Post reply on HN