In zsh
:
set -o extendedglob
zmodload zsh/system
bash_shebang_pattern=$'\\#! #(/usr/bin/env ##|(/usr(/local|)|/opt/gnu|)/bin/)bash[ \n]*'
improperly_named_bash_scripts=(
**/*.sh(ND.L+11f[a+x]e['
sysread -s80 shebang < $REPLY &&
[[ $shebang = $~bash_shebang_pattern ]]
'])
)
print -rl -- "These executable files have a .sh extension even though they're bash scripts:" $improperly_named_bash_scripts
That's widening a bit the possibilities of bash shebang, but note that possibilities are infinite if you want to consider BSD/GNU's env -S
like:
#! /usr/bin/env --split-str=-u\_BASH_ENV\_-u\_ENV\_-u\_POSIXLY_CORRECT\_-u\_LC_ALL\_PATH=/opt/gnu/bin:${PATH}\_LC_CTYPE=C\_LC_COLLATE=C\_bash\_-o\_errexit\_-o\_nounset\_-o\_pipefail\_--
Which some might prefer over:
#! /bin/bash -
(let alone #!/bin/bash
which strictly speaking is incorrect) to sanitize the environment a bit.
Details:
**/
any level of subdirectories.
*.sh
files whose name ends in .sh
(note: that includes the hidden file whose name is .sh
).
(ND.L+11f[a+x]e['code'])
: glob qualifiers:
N
: nullglob
D
: dotglob (include hidden files)
.
: regular files only (no directory, symlink, fifo, device...)
L+11
: L
ength greater than 11 bytes (the size of #!/bin/bash
)
f[a+x]
: for which the permissions include x
for a
ll.
e['code']
: runs the code to decide whether the file (in $REPLY
) should be selected.
sysread -s80
only read the first 80 bytes. Should be enough even for a #! /usr/bin/env bash
one. Not one line, as those could be huge for binary files which are not guaranteed to contain newline characters.
for
to select only the executable files with the format *.sh – Laura May 21 '20 at 22:59