Live data from Hacker News

Bash Debugging

wizardzines.com

21–30 of 78 posts

Re: Bash Debugging

#21

Is there a reason bash is still the de facto shell scripting language other than sheer momentum of legacy? I'm able to get what I need done in it, but it's clunky and the syntax is horrid. I guess it forces you to move to a proper language once scripts grow to a certain size/complexity, so perhaps it's by design?

bourne shell scripting is good enough, which makes it nearly impossible to replace. Plan9's rc is a bit cleaner, and no one is going to switch for 'more of the same, but cleaner'. You haven't switched to something similar but better even though you could literally do it right now https://pkgsrc.se/shells , and it doesn't run any different for anyone else. It usually takes something several times better in some crucial aspect to replace an entrenched technology. For example, Plan 9 is better than UNIX-like systems, but not good enough to replace them. I don't think it's possible to make something good enough to replace bourne shell scripting in its niche because before you have something several times better, good enough to actually replace it, you're in a different ecological niche or problem domain, for real scripting languages like Perl, Python, and Ruby. It's a local maximum solution that sucks the air out of the room for potential competition closer to the theoretical global maximum solution for the narrow problem domain.

Re: Bash Debugging

#22

The `die()` trick is good, but bash has an annoying quirk: if you try to `exit` while you're inside a subshell, then the subshell exits but the rest of the script continues. Example: #!/bin/bash die() { echo "$1" >&2; exit 1; } cat myfile | while read line; do if [[ "$line" =~ "information" ]]; then die "Found match" fi done echo "I don't want this line" ..."I don't want this line" will be printed. You can often avoi…

Could killing the PID like that create zombies?

Re: Bash Debugging

#23
post #2

Good stuff! I use set-x frequently and have used a similar thing to die (but Julia’s version is nicer). I’ll consider using the debugger thing but stepping through a bash script line by line sounds a bit tedious. Perhaps less so than having to reread a log and rerun the script a bunch.

I often add a fail-unless function: fail-unless() { local result "$@" result=$? if ((result != 0)); then echo >2&1 "Failed ${result} with command '$*'." exit ${result} fi } That way, I know exactly what failed in the script.

You do e.g. `fail-unless somecommand`. The result (exit/return code) is captured in the function and based on that, the function logs and exits or not.

Re: Bash Debugging

#24

Is there a reason bash is still the de facto shell scripting language other than sheer momentum of legacy? I'm able to get what I need done in it, but it's clunky and the syntax is horrid. I guess it forces you to move to a proper language once scripts grow to a certain size/complexity, so perhaps it's by design?

Are you sure it's bash? Most scripts on FreeBSD's are written for sh, which I feel is much more widely supported due to being part of the POSIX standard. Bash is just popular I think.

Bash is pretty much expected to be installed on any Linux distro. On FreeBSD (and likely other BSDs) it is an optional install. If you want a script to run on either, use sh. If strictly Linux, bash is probably safe.

Bash/sh is good for when you need to combine some commands and what needs to be done can be accomplished mostly by CLI commands with a little glue to tie them together. Some times it is surprising what can be accomplished. I wrote a program to import pictures from an SD card on Windows using C#, copying pictures to C:\Pictures\YYYY\MM\DD according to the EXIF data or failing that, file time stamp. I tried to port it to Linux but ran into problems trying to connect to the EXIF library. After struggling with that, I rewrote it using sh, some EXIF tool and various file utilities. It took 31 lines, about half of which were actual commands and the rest comments or white space.

A much bigger project is a script to install Debian with root on ZFS. It's mostly a series of CLI commands with some variable substitution and conditionals depending on stuff like encrypted or not.

Re: Bash Debugging

#25

Is there a reason bash is still the de facto shell scripting language other than sheer momentum of legacy? I'm able to get what I need done in it, but it's clunky and the syntax is horrid. I guess it forces you to move to a proper language once scripts grow to a certain size/complexity, so perhaps it's by design?

Are you sure it's bash? Most scripts on FreeBSD's are written for sh, which I feel is much more widely supported due to being part of the POSIX standard. Bash is just popular I think.

I suppose it’s an ambiguous designation.

I feel like when I see a shell script in my work, which is not in operating systems development of course, people are targeting bash. I agree many things are careful to target sh for certain reasons (e.g. a script that runs in a container where the base image doesn’t have bash installed) but i still think GP’s question is interesting because it’s not common to see, say, a zsh shell script, but seeing #!/bin/bash is super common.

Re: Bash Debugging

#26

The `die()` trick is good, but bash has an annoying quirk: if you try to `exit` while you're inside a subshell, then the subshell exits but the rest of the script continues. Example: #!/bin/bash die() { echo "$1" >&2; exit 1; } cat myfile | while read line; do if [[ "$line" =~ "information" ]]; then die "Found match" fi done echo "I don't want this line" ..."I don't want this line" will be printed. You can often avoi…

Could killing the PID like that create zombies?

Perhaps, but in any case I would never write code like this.

First of all, sending sigkill is literally overkill and perpetuates a bad practice. Send `TERM`. If it doesn't work, figure out why.

Secondly, subshells should be made as clear as possible and not hidden in pipes. Related, looping over `read` is essentially never the right thing to do. If you really need to do that, don't use pipes; use heredocs or herestrings.

Fourth, if you cannot avoid subshells and you want to terminate the full script on some condition, exit with a specific exit code from the subshell, check for it outside and terminate appropriately.

Re: Bash Debugging

#27

Earlier quoted context omitted.

I often add a fail-unless function: fail-unless() { local result "$@" result=$? if ((result != 0)); then echo >2&1 "Failed ${result} with command '$*'." exit ${result} fi } That way, I know exactly what failed in the script.

You do e.g. `fail-unless somecommand`. The result (exit/return code) is captured in the function and based on that, the function logs and exits or not.

You probably meant to reply to BeefySwain, right?

Re: Bash Debugging

#28
post #25

Earlier quoted context omitted.

Are you sure it's bash? Most scripts on FreeBSD's are written for sh, which I feel is much more widely supported due to being part of the POSIX standard. Bash is just popular I think.

I suppose it’s an ambiguous designation. I feel like when I see a shell script in my work, which is not in operating systems development of course, people are targeting bash. I agree many things are careful to target sh for certain reasons (e.g. a script that runs in a container where the base image doesn’t have bash installed) but i still think GP’s question is interesting because it’s not common to see, say, a zsh…

I have done some delightful stuff in `zsh`, but I always lament how slow its numerical array traversal is. Frustratingly, experts told me it really doesn't have to be slow, the devs just don't seem to be bothering to revamp the underlying data structure because they are focusing more on associative arrays.

Re: Bash Debugging

#29

If I ever have to debug anything in bash. I stop using bash hah.

I find such reasoning backwards. Indeed, shell scripting is not friendly to debugging. But ensuring correctness of shell scripts is essential: usually, they touch part of your "$HOME" or system folders and do tons of I/O, some of it destructive. I find it baffling to see people write careless scripts; sometimes using `rm` for cleanup with unquoted parameters, or much worse, dangerous uses of `mv`.

Re: Bash Debugging

#30
post #13

Good info. You can improve your debugging by using exit codes like this: # die: print error message to stderr, then exit with error code. # example: die 69 "Service unavailable." die() { n="$1" ; shift ; >&2 printf %s\\n "$*" ; exit "$n" } Many more shell script exit codes and helper functions: https://github.com/SixArm/unix-shell-script-kit/blob/main/un...

That's a nice list; I guess every experienced user has their helper functions. However, I have a small criticism for the philosophy of that `die`: `die` functions should pass by default the exit code of the failed command, and not silence its error output. If I want to give my own meaning to the command failure in a large script for instance, I will use a different, more specialized `die`. My own die is roughly as follows:

    __errex() {
     printf 'Fatal error [%s] on line %s in '"'"'%s'"'"': %s\n' \
            "${1:-"?"}"                                         \
            "${2:-"?"}"                                         \
            "${3:-"unknown script"}"                            \
            "${4:-"unknown error"}" >&2                         ;
     exit "${1:-1}"
    }
    alias die='__errex "$?" "${LINENO}" "$0"'
Post reply on HN