summaryrefslogtreecommitdiff
path: root/src/content/tils/2021/01/17/posix-shebang.adoc
blob: 4e2fbe84ed466c15e515f46ce24f8f3ad6ac82ba (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
= POSIX sh and shebangs

:awk-1: link:../../../2020/12/15/shellcheck-repo.html
:awk-2: link:../12/curl-awk-emails.html

As I {awk-1}[keep moving] {awk-2}[towards POSIX], I'm on the process of
migrating all my Bash scripts to POSIX sh.

As I dropped `[[`, arrays and other Bashisms, I was left staring at the first
line of every script, wondering what to do: what is the POSIX sh equivalent of
`#!/usr/bin/env bash`?  I already knew that POSIX says nothing about shebangs,
and that the portable way to call a POSIX sh script is `sh script.sh`, but
I didn't know what to do with that first line.

What I had previously was:

[source,shell]
----
#!/usr/bin/env bash
set -Eeuo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")"
----

Obviously, the `$BASH_SOURCE` would be gone, and I would have to adapt some of
my scripts to not rely on the script location.  The `-E` and `-o pipefail`
options were also gone, and would be replaced by nothing.

I converted all of them to:

[source,shell]
----
#!/bin/sh -eu
----

I moved the `-eu` options to the shebang line itself, striving for conciseness.
But as I changed callers from `./script.sh` to `sh script.sh`, things started to
fail.  Some tests that should fail reported errors, but didn't return 1.

My first reaction was to revert back to `./script.sh`, but the POSIX bug I
caught is a strong strain, and when I went back to it, I figured that the
callers were missing some flags.  Specifically, `sh -eu script.sh`.

Then it clicked: when running with `sh script.sh`, the shebang line with the sh
options is ignored, as it is a comment!

Which means that the shebang most friendly with POSIX is:

[source,shell]
----
#!/bin/sh
set -eu
----

. when running via `./script.sh`, if the system has an executable at `/bin/sh`,
  it will be used to run the script;
. when running via `sh script.sh`, the sh options aren't ignored as previously.

TIL.