Live data from Hacker News

Pure Sh Bible

github.com

131–138 of 138 posts

Re: Pure Sh Bible

#131
post #121

Earlier quoted context omitted.

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?

Seems like there are different interpretations by authors/maintainers of what is required versus what is optional.

As an ordinary user, I am most interested, perhaps mistakenly, in POSIX for a single reason: portability. (Whether portability is a goal of POSIX I am not sure. I have not done much research. Maybe it isn't.) As a user, I want to be able to write scripts on Linux than run on BSD and vice versa. Perhaps I have conflated portability with "POSIX compliance". However, as a practical matter, I would not use these operators in scripts that I wanted to be portable. When I have the motivation, I am working on a unenhanced port of NetBSD sh to Linux, i.e., without the Herbert Xu changes. Being lazy, so far I just added tab completion to dash so it feels more like NetBSD sh.

The "Bible" I would be interested in reading, if it exists. is the "Portable Sh Bible". (I am not a Bash user.) When I have a question I usually consult https://www.in-ulm.de/~mascheck/

Re: Pure Sh Bible

#132
post #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}"…

All great comments, thank you! I feel the need to reply, even though there isn't a real need to, but here goes:

1. True; but in this case we're talking about bash specifically, so I prefer to use cleaner syntax whenever this is available. I find ${var+x} a bit too hacky ...

2. Huh, I was under the impression that bespoke commands overrode builtins. Good to know. What the hell is even the reason to have a 'builtin' keyword then ... just for "alias test=/usr/bin/test" style scenarios??

3. True about $#. Not sure why I didn't think of that, d'oh.

4. Thanks re Shellcheck. I do have it in mind, and was planning to use it prior to releasing a v1; but process_optargs came out of a larger project which is still in v0 (https://git.sr.ht/~tpapastylianou/bashtickets), and I only forked it into its own thing because someone asked me about it on HN, so I lost track. Thanks for the reminder. Having said that, I can't see why the error you describe would occur in this instance. Would you mind explaining? Why would the presence of a single-letter filename have anything to do with the piped output to tr?

5. Good point about printf (or about habitually passing "--" as an argument to things, I guess).

Thanks again!

Re: Pure Sh Bible

#133
post #46

Earlier quoted context omitted.

that bash you see is actually a symlink to ash

Did you download the busybox64.exe binary and execute it? I'm confident that it is presented. I use this to spray SQL to dozens of databases.

The bash you're seeing is a symlink to busybox, as are all busybox applets.

You can configure busybox to install an applet named "bash", but it's not a full bash shell. It's basically busybox ash, with maybe a few bash-specific extensions implemented. For example, it doesn't support arrays; `arr=(10 20)` will give you a syntax error.

In a default configuration, there is no "bash" applet. You can optionally configure busybox to alias "bash" to either "ash" or "hush" (and likewise for "sh"). This allows the use of "#!/bin/bash" scripts, but only if they don't use bash-specific features not supported by busybox.

Re: Pure Sh Bible

#134
post #127

Earlier quoted context omitted.

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}"…

All great comments, thank you! I feel the need to reply, even though there isn't a real need to, but here goes: 1. True; but in this case we're talking about bash specifically, so I prefer to use cleaner syntax whenever this is available. I find ${var+x} a bit too hacky ... 2. Huh, I was under the impression that bespoke commands overrode builtins. Good to know. What the hell is even the reason to have a 'builtin' ke…

> I can't see why the error you describe would occur in this instance. Would you mind explaining?

Sure, it's due to pathname expansion. The most commonly used pattern is `*` (e.g. `echo *.txt` might expand to `echo foo.txt bar.txt`), but there is also `[...]` for matching a character range. If the current directory contains files named "i" and "j", then `tr -s [:alpha:] Y` will expand to `tr -s i j Y`, which is not what you want. (The reason it works when the current directory doesn't contain single-letter filenames is that a pattern which doesn't match any filenames is left as-is.)

Re: Pure Sh Bible

#135
post #126

Earlier quoted context omitted.

> 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).

[deleted]

Re: Pure Sh Bible

#136
post #134

Earlier quoted context omitted.

All great comments, thank you! I feel the need to reply, even though there isn't a real need to, but here goes: 1. True; but in this case we're talking about bash specifically, so I prefer to use cleaner syntax whenever this is available. I find ${var+x} a bit too hacky ... 2. Huh, I was under the impression that bespoke commands overrode builtins. Good to know. What the hell is even the reason to have a 'builtin' ke…

> I can't see why the error you describe would occur in this instance. Would you mind explaining? Sure, it's due to pathname expansion. The most commonly used pattern is `*` (e.g. `echo *.txt` might expand to `echo foo.txt bar.txt`), but there is also `[...]` for matching a character range. If the current directory contains files named "i" and "j", then `tr -s [:alpha:] Y` will expand to `tr -s i j Y`, which is not w…

Ah right, gotcha. Actually I think `i` and `j` would be fine, since the whole point is that [:alpha:] will expand to any of the characters contained in that range before it has a chance to be interpreted as the intended character class (and therefore, i and j are safe from accidental pathname expansion, since they don't appear in that range).

But yes, this indeed causes problems if you have a file called `:`, `a`, `l`, `p`, or `h` on the system.

Good catch. Thanks again.

Re: Pure Sh Bible

#137
post #134

Earlier quoted context omitted.

> I can't see why the error you describe would occur in this instance. Would you mind explaining? Sure, it's due to pathname expansion. The most commonly used pattern is `*` (e.g. `echo *.txt` might expand to `echo foo.txt bar.txt`), but there is also `[...]` for matching a character range. If the current directory contains files named "i" and "j", then `tr -s [:alpha:] Y` will expand to `tr -s i j Y`, which is not w…

Ah right, gotcha. Actually I think `i` and `j` would be fine, since the whole point is that [:alpha:] will expand to any of the characters contained in that range before it has a chance to be interpreted as the intended character class (and therefore, i and j are safe from accidental pathname expansion, since they don't appear in that range). But yes, this indeed causes problems if you have a file called `:`, `a`, `l…

Oops, quite right -- the glob pattern for matching any letter is `[[:alpha:]]`, not `[:alpha:]`. Cheers!

Re: Pure Sh Bible

#138
post #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}"…

Edit: That should have been `[ "${myvar+set}" = "set" ]` for checking that `myvar` is set.
Post reply on HN