Live data from Hacker News

Pure Sh Bible

github.com

121–130 of 138 posts

Re: Pure Sh Bible

#121
post #85

Earlier quoted context omitted.

Those operators are in "2.6.4 Arithmetic Expansion" in your linked doc. See the link to "Arithmetic Precision and Operations"[1]. [1]: https://web.archive.org/web/20201219013931/https://pubs.open...

Thank you. This helps. But does that mean a POSIX shell, or any other UNIX utility, must implement these operators. Using them in shell scripts makes the scripts non-portable, e.g., Almquist sh, NetBSD Almquist sh or Debian Almquist sh do not support them. Maybe the author of the "Pure POSIX Sh Bible" always runs Bash in --posix mode. Hence "Pure POSIX sh".

Well it doesn't say that arithmetic expansion is "optional" or an "extension". Maybe those shells are conforming to an older version?

Re: Pure Sh Bible

#122
post #75

Earlier quoted context omitted.

It's well worth learning to use printf instead of echo to avoid all the various ways that echo can break or is not well defined. https://mywiki.wooledge.org/BashPitfalls#echo_.24foo

The %q format alone justifies learning about printf. Vanilla echo is for chumps.

Note that this is supported by bash/zsh/ksh but not by POSIX sh.

Re: Pure Sh Bible

#123
post #85

Earlier quoted context omitted.

Those operators are in "2.6.4 Arithmetic Expansion" in your linked doc. See the link to "Arithmetic Precision and Operations"[1]. [1]: https://web.archive.org/web/20201219013931/https://pubs.open...

Thank you. This helps. But does that mean a POSIX shell, or any other UNIX utility, must implement these operators. Using them in shell scripts makes the scripts non-portable, e.g., Almquist sh, NetBSD Almquist sh or Debian Almquist sh do not support them. Maybe the author of the "Pure POSIX Sh Bible" always runs Bash in --posix mode. Hence "Pure POSIX sh".

They've been in dash for a pretty long time. NetBSD has lagged behind a bit. http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=50...

This just means that you're going to have to find a better way to describe the level of backwards compatibility you're going for other than "POSIX compliance", because these do seem to be required in the standards.

Re: Pure Sh Bible

#124
post #7

I have to take exception to some of this; it's "technically correct" but like much of shell, likely full of terrifying edge cases that are best avoided. For instance, using eval to have variables with variable names is madness. $ var="world" $ eval "hello_$var=value" $ eval printf '%s\n' "\$hello_$var" I suppose the fancy business with printf is flexing, but I suspect the majority of people scanning documents like th…

I'm scratching my head at most of it and there's large portions that are incomplete or trivial. bash is ubiquitous. If you're trying to develop an entire web framework to run on a Bourne shell from busybox, dash, or FreeBSD 4, there's probably a better way to do it. Use the tool you have, not a hypothetical one compatible with 1983. YAGNI. Here's a common pattern for appending to PATH system-wide once: # /etc/profile…

Your "zsh/bash" code doesn't actually use any zsh/bash-only features, so it is compatible with POSIX sh. But you have a quoting bug: you should escape the `$` in `$2` and `${3...}` to protect from double-eval.

I'd personally try to minimise the use of eval, e.g.

    prepend() {
        local val
        eval "val=\$$1"
        export "$1=$2${val:+${3-:}$val}"
    }

    append() {
        local val
        eval "val=\$$1"
        export "$1=${val:+$val${3-:}}$2"
    }

Re: Pure Sh Bible

#125
post #7

I have to take exception to some of this; it's "technically correct" but like much of shell, likely full of terrifying edge cases that are best avoided. For instance, using eval to have variables with variable names is madness. $ var="world" $ eval "hello_$var=value" $ eval printf '%s\n' "\$hello_$var" I suppose the fancy business with printf is flexing, but I suspect the majority of people scanning documents like th…

It's well worth learning to use printf instead of echo to avoid all the various ways that echo can break or is not well defined. https://mywiki.wooledge.org/BashPitfalls#echo_.24foo

Yes. printf is not a "flex", it's the only safe way to display arbitrary strings. The link mentions one good reason to avoid echo (string might be "-n"), but another important reason is that the behaviour of echo is implementation-defined if the string contains backslashes (e.g. `echo 'foo\nbar'` displays one line in bash but two lines in dash and zsh).

Re: Pure Sh Bible

#126

Earlier quoted context omitted.

> where things get easier if you just switch to a language with less caveats (like Python). For general, non-domain specific things, it gets IMO easier by two main reasons 1) obviously when using tools where one has more experience with, but 2) also when the tool is more widely available, and POSIX shell is probably one of the most (by default) available interpreters with a somewhat human-friendly input mode there is…

> They use the printf "%f" float format conversion so `printf "%f" 2e3` will work just fine, whereas using something that definitively is not a float makes printf exit with an error code as it fails to format the value as float, failing this check. You are of course correct (sorry to sound like a language model), I missed the printf.

Actually, the function returns success if the input contains "." and printf succeeds, so it does not consider 2e3 to be a float. I agree that this function is odd (it's not even useful for identifying simple numbers of the form "123.456", because it considers 2.0e3 to be a float).

Re: Pure Sh Bible

#127

Regarding conditional expressions: I found something neat recently. The coreutils version of `test` doesn't have this, and when you use `test`, typically what you're using is the coreutils one. But if you use `builtin test` to force the bash builtin variant of `test`, this has a nice `-v` switch, which allows you to check if a variable is set. I found out about this recently when I had to use it in my bash argument p…

Note that `test -v` is not in POSIX sh (see https://pubs.opengroup.org/onlinepubs/9699919799/utilities/t...). And you don't need `builtin` because `test ...` invokes the builtin by default; if you want to run coreutils test you need to use `/usr/bin/test ...` or `env test ...` or `(exec test ...)`.

The usual way to check if $2 is present is to use `[ $# -ge 2 ]`. For named variables, I like to use `[ "${myvar+set}" != "set" ]` (the parameter expansion `${myvar+word}` expands to "word" if myvar is set or "" if it is unset, see https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V...).

(Often people want to treat an empty value as unset, so they just use `[ -n "$myvar" ]` to check that the value is non-empty. If you enable `set -u` to treat references to unset variables as errors, this should instead be `[ -n "${myvar-}" ]`.)

Some comments on the script you linked:

I highly recommend ShellCheck (https://www.shellcheck.net/), it picks up a legitimate issue in your script: `tr -s [:alpha:] Y` should be `tr -s "[:alpha:]" Y` (otherwise it fails if the current directory contains a single-letter filename).

Also, you should use `printf "%s\n" "$var"` instead of `echo "$var"` in case $var is "-n" for example.

Re: Pure Sh Bible

#128
post #57

Regarding conditional expressions: I found something neat recently. The coreutils version of `test` doesn't have this, and when you use `test`, typically what you're using is the coreutils one. But if you use `builtin test` to force the bash builtin variant of `test`, this has a nice `-v` switch, which allows you to check if a variable is set. I found out about this recently when I had to use it in my bash argument p…

If you already assume bash, then you don’t need the “-v” option to the “test” builtin; just do if [ "${foo+some_string}" = "" ]; then echo "foo is unset" fi or, in your case: if test "${2+x}" = "" # i.e. if $2 is not set

In fact `${foo+some_string}` is supported by POSIX sh (unlike `test -v`).

Re: Pure Sh Bible

#129
post #49

i dont know about anyone else. but since ChatGPT, my shell game is probably the one that is most levelled up. A lot of things i would either do manually because i had forgotten shell programming, or i would have done in a seperate pyenv with 2-3 packages i can get done in about 4 minutes.

Beware, I would not trust ChatGPT to produce safe scripts. At minimum, consider using ShellCheck on the result to detect common mistakes such as not quoting variables. Writing safe scripts is very hard.

Re: Pure Sh Bible

#130
post #124

Earlier quoted context omitted.

I'm scratching my head at most of it and there's large portions that are incomplete or trivial. bash is ubiquitous. If you're trying to develop an entire web framework to run on a Bourne shell from busybox, dash, or FreeBSD 4, there's probably a better way to do it. Use the tool you have, not a hypothetical one compatible with 1983. YAGNI. Here's a common pattern for appending to PATH system-wide once: # /etc/profile…

Your "zsh/bash" code doesn't actually use any zsh/bash-only features, so it is compatible with POSIX sh. But you have a quoting bug: you should escape the `$` in `$2` and `${3...}` to protect from double-eval. I'd personally try to minimise the use of eval, e.g. prepend() { local val eval "val=\$$1" export "$1=$2${val:+${3-:}$val}" } append() { local val eval "val=\$$1" export "$1=${val:+$val${3-:}}$2" }

(`local` is not in POSIX, I know)
Post reply on HN