A Little About Shebang in Linux
Greetings!

Shebang is the #! sequence at the beginning of an executable file that tells the system which program should interpret this script📝. A popular shebang for bash is #!/bin/bash. Its peculiarity is that it strictly points to a specific path in the file system: /bin/bash. This is fair if you know for sure that bash is actually located at this path🛣️.

Everything would be fine, but there are nuances🤷‍♂️. First, in most Linux distributions, bash is installed in /usr/bin/bash, which can already make your script fail. To avoid this, the system creates a symbolic link /bin pointing to the /usr/bin directory:

BASH
ls -ld /bin
Click to expand and view more
PLAINTEXT
Permissions Size User Group Date Modified    Name
lrwxrwxrwx     7 root root  2023-09-22 19:26 /bin -> usr/bin
Click to expand and view more

The conclusion suggests itself: specify /usr/bin/bash as the shebang, but even this is not a universal solution🤔. In some distributions, the bash binary may still be located elsewhere.

That is why #!/usr/bin/env bash is often used as the shebang💡.

env is a utility for working with environment variables. In the case of bash, before launching, the env utility searches for the binary in the $PATH variable, which contains a list of directories with executable files separated by the : character. For example:

BASH
/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
Click to expand and view more

This shebang option is more universal: if bash is installed in a non-standard location but is available through PATH, it will be found. This behavior is the same in Linux, macOS, BSD, and virtual environments😌.

But there are also disadvantages😠. This launch method is slightly less efficient (there is an extra env call), and in rare situations the “wrong” bash may be launched if there are different versions in PATH. For example, there are two different bashes: /usr/local/bin/bash and /usr/bin/bash. With the PATH specified above, /usr/local/bin/bash will be used.

You can see the difference in how shebangs work using the strace system call tracing tool, also known as “ostrich”🐓.

Create two scripts and make them executable:

BASH
cat > test-bin.sh <<EOF
#!/bin/bash
echo "I am /bin/bash"
EOF

cat > test-env.sh <<EOF
#!/usr/bin/env bash
echo "I am env bash"
EOF

chmod +x test-bin.sh test-env.sh
Click to expand and view more

Run the first one with strace and filter the output by the execve call:

BASH
strace -f -e trace=execve -s 200 ./test-bin.sh
Click to expand and view more

We see only one call:

PLAINTEXT
execve("./test-bin.sh", ["./test-bin.sh"], 0x7ffe817c2458 /* 37 vars */) = 0
I am /bin/bash
+++ exited with 0 +++
Click to expand and view more

Now run the variant with env:

BASH
strace -f -e trace=execve -s 200 ./test-env.sh
Click to expand and view more

Here the output will be noticeably longer. You can see that the executable file is searched for in several directories:

PLAINTEXT
strace -f -e trace=execve -s 200 ./test-env.sh 2>&1
execve("./test-env.sh", ["./test-env.sh"], 0x7ffd9fe2e898 /* 37 vars */) = 0
execve("/usr/local/sbin/bash", ["bash", "./test-env.sh"], 0x7ffcaca77068 /* 37 vars */) = -1 ENOENT (No such file or directory)
execve("/usr/local/bin/bash", ["bash", "./test-env.sh"], 0x7ffcaca77068 /* 37 vars */) = -1 ENOENT (No such file or directory)
execve("/usr/sbin/bash", ["bash", "./test-env.sh"], 0x7ffcaca77068 /* 37 vars */) = -1 ENOENT (No such file or directory)
execve("/usr/bin/bash", ["bash", "./test-env.sh"], 0x7ffcaca77068 /* 37 vars */) = 0
I am env bash
+++ exited with 0 +++
Click to expand and view more

Interestingly, the search order does not fully match the order of directories in PATH. Alternating, *sbin is checked first, then *bin🤔.

Nevertheless, it is recommended to use exactly #!/usr/bin/env bash for greater universality👍. It is worth noting that this approach is valid for any interpreters, for example #!/usr/bin/env python, #!/usr/bin/env awk, and so on.

Copyright Notice

Author: Иван Чёрный

Link: https://r4ven.me/en/automation/nemnogo-pro-shebang-v-linux/

License: CC BY-NC-SA 4.0

Использование материалов блога разрешается при условии: указания авторства/источника, некоммерческого использования и сохранения лицензии.

Start searching

Enter keywords to search articles

↑↓
ESC
⌘K Shortcut