Live data from Hacker News

“Exit traps” can make your Bash scripts more robust and reliable (2013)

redsymbol.net

71–80 of 159 posts

Re: “Exit traps” can make your Bash scripts more robust and reliable (2013)

#71

Earlier quoted context omitted.

How have exit traps come back to bite you?

The first is that the trap can come at any time. You can't assume at what point in the script it was running, so you have to test for different cases to find out what you now can/should do. Forget an edge case and now you've got an extra bug. Not using traps, it's clearer what happens at specific points in the execution of the rest of the code, so simpler to reason about how to deal with those cases as/where they hap…

There's a bit more nuance in my opinion.

If your cleanup logic is no more complicated than "perform some cleanup whenever the script exits for any reason, without concern for what state the things to clean up are in", I think trapping everything and calling the cleanup function is fine.

If you have to do anything more complicated, it's probably a better idea to stick all that logic into a non-bash program. You can do it in Bash if you know what you're doing, but it's going to be ugly, hacky, error-prone, and tedious.

    Not using traps, it's clearer what happens at specific points in the execution of the rest of the code, so simpler to reason about how to deal with those cases as/where they happen.
You can stick all kinds of logic into the cleanup function, but again, it's ugly.

    The second is different events can trigger an exit trap, and those may have different implications on what's going on.
    The third is there's parts of standards left out about what happens during/after a trap or when they get called, what data you have available, and different implementations can behave differently.
Which is why I think it's preferable not to do this in bash if you have any concern for why the program is exiting

    Fourth is that sometimes people will use an exit trap to, say, report on a failure, but they may have lost context of what block they were in when it exited, and now the error reporting doesn't tell you everything you wanted to know.
If you need any tracing, the only way this makes sense in bash is when running with -evx (errexit, verbose, trace) so you know exactly where you exited. This isn't always a bad idea, though -vx probably is most of the time.

If you think you can do any complex logic in the trap function then you have to consider whether that logic might fail at any point, and depending on the signal there's a good chance you're on a clock as well.

Re: “Exit traps” can make your Bash scripts more robust and reliable (2013)

#72
post #8

[flagged]

A good read before dismissing http://n-gate.com/software/2017/

I disagree with his disagreement. I'm not able to overthrow my government to make it illegal for my only ISP to stop intercepting my traffic. HTTPS simply makes it impossible for my ISP to add stuff to the page in transit.

Re: “Exit traps” can make your Bash scripts more robust and reliable (2013)

#74
post #65

>The secret sauce is a pseudo-signal provided by bash, called EXIT, that you can trap; commands or functions trapped on it will execute when the script exits for any reason. "Secret Sauce", why is this secret at all. Nothing against the author who's helping the ecosystem here, but is there an authoritative guide on Bash that anyone can recommend? Hopefully something that's portable between Mac & Linux. The web is ful…

It's secret enough to be well documented in the man page. The real question is, why do people look to random web pages prior to having digested everything in the manual? People used to say "rtfm" all the time, this would be regarded as shockingly rude in today's tech culture but it was a valuable public service to have it repeated, like being reminded to eat your vegetables.

Because ain't nobody got time for that. ;)

More seriously, I think that we have been trained to rely on just in time searches (or ChatGPT sessions) when we encounter the next thing we need to learn. RTFM is just so time consuming and I personally don't recall everything I have read, leading me to rely on search/AI to re-learn the next thing just in time anyways.

In some ways this is a vast improvement, which is why it's the default behavior now. Why cream your brain with information you might never use?

But it DEFINITELY has a weakness in that you don't know what you don't know. I never knew about this 'trap' trick, for example... and I didn't know I didn't know it, despite it being something I see as quite useful.

Side note: I think RTFM has historically meant "try to find the answer first before asking for it", leading to me designating LMGTFY (Let Me Google That For You) as the modern equivalent in this just in time searches reality we live in. I wonder how long it will be before we start saying LMAAIFY (Let Me Ask AI For You)...

Re: “Exit traps” can make your Bash scripts more robust and reliable (2013)

#75
post #68

Earlier quoted context omitted.

The first is that the trap can come at any time. You can't assume at what point in the script it was running, so you have to test for different cases to find out what you now can/should do. Forget an edge case and now you've got an extra bug. Not using traps, it's clearer what happens at specific points in the execution of the rest of the code, so simpler to reason about how to deal with those cases as/where they hap…

As with most things in programming, it sounds like if you use the wrong tool for the wrong job, then you're prone to writing bugs. Using traps is a great idea when used properly and dismissing it outright isn't doing anyone any favors.

I agree with you but also the person you're responding to; I think the article sells traps too hard as a handy multi-purpose tool like a swiss army knife, when they're really more like a letter-opener; there are situations where it makes sense to use them, but you'd usually be better off with something else, and not knowing the difference can result in trying to use it as a precision blade, which ends up mangling things.

Re: “Exit traps” can make your Bash scripts more robust and reliable (2013)

#76
https://github.com/DaveJarvis/keenwrite/blob/main/scripts/bu...

My template script provides a way to make user-friendly shell scripts. In a script that uses the template, you define the dependencies and their sources as comma-separated values:

    DEPENDENCIES=(
      "gradle,https://gradle.org"
      "warp-packer,https://github.com/Reisz/warp/releases"
      "tar,https://www.gnu.org/software/tar"
      "wine,https://www.winehq.org"
      "unzip,http://infozip.sourceforge.net"
    )
You define the command-line arguments:

    ARGUMENTS+=(
      "a,arch,Target operating system architecture (amd64)"
      "o,os,Target operating system (linux, windows, mac)"
      "u,update,Java update version number (${ARG_JAVA_UPDATE})"
      "v,version,Full Java version (${ARG_JAVA_VERSION})"
    )
You define the "execute()" method that is called after the arguments are parsed:

    execute() {
      // Make the computer do the work.

      return 1
    }
If the script takes arguments, handle each one individually:

    argument() {
      local consume=2

      case "$1" in
        -a|--arch)
        ARG_JAVA_ARCH="$2"
        ;;
        -o|--os)
        ARG_JAVA_OS="$2"
        ;;
      esac

      return ${consume}
    }
Then call the template's main to start the script rolling:

    main "$@"
For 99% of the scripts I write, this provides:

* Built-in software dependencies verification.

* Instructions to the user when requirements are missing.

* Simple command-line argument parsing.

* Help and logging using ANSI colour.

Here's a complete script that builds the Windows, Linux, and Mac installers for my Markdown editor:

https://github.com/DaveJarvis/KeenWrite/blob/main/installer....

There's a write-up about creating the script that has a lot more details about how the template works:

https://dave.autonoma.ca/blog/2019/05/22/typesetting-markdow...

Note that it is technically possible to improve the scripts such that handling individual arguments can be done in the template itself. This would require a slightly different argument definition semantics:

    ARGUMENTS+=(
      "ARG_JAVA_ARCH,a,arch,Target operating system architecture (amd64)"
      "ARG_JAVA_OS,o,os,Target operating system (linux, windows, mac)"
      "usage=utile_usage,h,help,Show this help message then exit"    
    )
By detecting an `=` symbol for the first item in the lists, it's possible to know whether a command-line argument is assigning a variable value, or whether it means to perform additional functionality. (PR welcome!)

Re: “Exit traps” can make your Bash scripts more robust and reliable (2013)

#78

Don't use traps unless you have to. They are subtly complex and require a great deal more code to deal with edge cases. There is almost always a simpler way to accomplish what you want. If Bash has taught me anything, it's that many advanced features should seldom be used. Always resist the temptation to be fancy.

How have exit traps come back to bite you?

    # usage : utility NEW_DIRECTORY -- user : I think not
    #
    trap 'cleanup' INT HUP TERM
    cleanup() { rm -rf "${mydir}" ;}
    
    # stuff
    mydir="${HOME}/$1" # but $1 is empty
    if test -z "$1"; then
        # handle; but while stuff is happening,
        # user presses Ctrl-C
    fi

Re: “Exit traps” can make your Bash scripts more robust and reliable (2013)

#79
post #39
post #7

An annoying thing about bash is that EXIT will also run on SIGINT (^C), which most other shells won't (in my reading it's also not POSIX compliant, although the document is a bit vague). Some might argue this is a feature, but IMHO it's a bug – sometimes you really don't want cleanup to happen so people can inspect the contents of temporary files for debugging. Because trap doesn't pass the signal information to the…

> Because trap doesn't pass the signal information to the handler You can examine $? on entry to the trap function. On signals, it will be 128 + signal. i.e. on TERM (15) it will be 143. On INT (2) it will be 130. #!/bin/bash skip_exit= on_exit() { code=$? if test $code == 130; then skip_exit=1 fi if test -n "$skip_exit"; then return fi echo "Exiting with: $code" return $code } trap on_exit INT EXIT sleep 2 false Wit…

I mean, it's possible, but it's not exactly pretty, and it won't necessarily work in all POSIX compliant shells either (although I believe it will in most, but I didn't test – things the trap execution order and exact status codes are not exactly defined IIRC).

Re: “Exit traps” can make your Bash scripts more robust and reliable (2013)

#80

Earlier quoted context omitted.

Why not?

The program could get paused mid-execution. Moreover, I’m pretty sure a malicious process can put file watchers in /tmp and read all written contents.

If your script calls

  umask 077
...before creating temp files then they won't be world-readable. Still lots of pitfalls. (What user are you running as, and who else is running as that user? What's the mount point file system, and does it have POSIX permissions? Why are you persisting secrets to disk in the first place? Etc.)
Post reply on HN