2020-10-26 18:06:03 +00:00
|
|
|
#!/bin/sh
|
2016-05-12 04:22:25 +00:00
|
|
|
#
|
2019-12-31 06:36:56 +00:00
|
|
|
# Copyright 2013-2020 Lawrence Livermore National Security, LLC and other
|
2020-10-28 21:07:05 +00:00
|
|
|
# sbang project developers. See the top-level COPYRIGHT file for details.
|
2016-05-12 04:22:25 +00:00
|
|
|
#
|
2018-10-07 20:52:23 +00:00
|
|
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
|
|
|
|
2016-03-05 12:18:48 +00:00
|
|
|
#
|
|
|
|
# `sbang`: Run scripts with long shebang lines.
|
|
|
|
#
|
2020-10-26 18:06:03 +00:00
|
|
|
# Many operating systems limit the length and number of possible
|
|
|
|
# arguments in shebang lines, making it hard to use interpreters that are
|
|
|
|
# deep in the directory hierarchy or require special arguments.
|
|
|
|
#
|
2020-10-28 21:07:05 +00:00
|
|
|
# To use, put the long shebang on the second line of your script, and
|
|
|
|
# make sbang the interpreter, like this:
|
2016-03-05 12:18:48 +00:00
|
|
|
#
|
2020-10-28 21:07:05 +00:00
|
|
|
# #!/bin/sh /path/to/sbang
|
|
|
|
# #!/long/path/to/real/interpreter with arguments
|
2016-03-05 12:18:48 +00:00
|
|
|
#
|
2020-10-28 21:07:05 +00:00
|
|
|
# `sbang` will run the real interpreter with the script as its argument.
|
2016-03-05 12:18:48 +00:00
|
|
|
#
|
2020-10-28 21:07:05 +00:00
|
|
|
# See https://github.com/spack/sbang for more details.
|
2016-03-05 12:18:48 +00:00
|
|
|
#
|
2020-10-26 18:06:03 +00:00
|
|
|
|
|
|
|
# Generic error handling
|
|
|
|
die() {
|
|
|
|
echo "$@" 1>&2;
|
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
|
|
|
|
# set SBANG_DEBUG to make the script print what would normally be executed.
|
|
|
|
exec="exec"
|
|
|
|
if [ -n "${SBANG_DEBUG}" ]; then
|
|
|
|
exec="echo "
|
|
|
|
fi
|
|
|
|
|
2016-03-05 12:18:48 +00:00
|
|
|
# First argument is the script we want to actually run.
|
|
|
|
script="$1"
|
|
|
|
|
2020-10-26 18:06:03 +00:00
|
|
|
# ensure that the script actually exists
|
|
|
|
if [ -z "$script" ]; then
|
|
|
|
die "error: sbang requires exactly one argument"
|
|
|
|
elif [ ! -f "$script" ]; then
|
|
|
|
die "$script: no such file or directory"
|
|
|
|
fi
|
|
|
|
|
2016-03-05 12:18:48 +00:00
|
|
|
# Search the first two lines of script for interpreters.
|
|
|
|
lines=0
|
2020-10-26 18:06:03 +00:00
|
|
|
while read -r line && [ $lines -ne 2 ]; do
|
|
|
|
if [ "${line#\#!}" != "$line" ]; then
|
|
|
|
shebang_line="${line#\#!}"
|
|
|
|
elif [ "${line#//!}" != "$line" ]; then # // comments
|
|
|
|
shebang_line="${line#//!}"
|
|
|
|
elif [ "${line#--!}" != "$line" ]; then # -- lua comments
|
|
|
|
shebang_line="${line#--!}"
|
|
|
|
elif [ "${line#<?php\ }" != "$line" ]; then # php comments
|
|
|
|
shebang_line="${line#<?php\ \#!}"
|
|
|
|
shebang_line="${shebang_line%\ ?>}"
|
2016-03-05 12:18:48 +00:00
|
|
|
fi
|
|
|
|
lines=$((lines+1))
|
|
|
|
done < "$script"
|
|
|
|
|
2020-10-26 18:06:03 +00:00
|
|
|
# error if we did not find any interpreter
|
2020-10-28 21:07:05 +00:00
|
|
|
if [ -z "$shebang_line" ]; then
|
2020-10-26 18:06:03 +00:00
|
|
|
die "error: sbang found no interpreter in $script"
|
|
|
|
fi
|
|
|
|
|
2020-10-28 21:07:05 +00:00
|
|
|
# parse out the interpreter and first argument
|
|
|
|
IFS=' ' read -r interpreter arg1 rest <<EOF
|
|
|
|
$shebang_line
|
|
|
|
EOF
|
|
|
|
|
2020-10-26 18:06:03 +00:00
|
|
|
# Determine if the interpreter is a particular program, accounting for the
|
|
|
|
# '#!/usr/bin/env PROGRAM' convention. So:
|
|
|
|
#
|
|
|
|
# interpreter_is perl
|
|
|
|
#
|
|
|
|
# will be true for '#!/usr/bin/perl' and '#!/usr/bin/env perl'
|
|
|
|
interpreter_is() {
|
|
|
|
if [ "${interpreter##*/}" = "$1" ]; then
|
|
|
|
return 0
|
|
|
|
elif [ "$interpreter" = "/usr/bin/env" ] && [ "$arg1" = "$1" ]; then
|
|
|
|
return 0
|
2016-09-22 07:43:47 +00:00
|
|
|
else
|
2020-10-26 18:06:03 +00:00
|
|
|
return 1
|
2016-09-22 07:43:47 +00:00
|
|
|
fi
|
2020-10-26 18:06:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if interpreter_is "sbang"; then
|
|
|
|
die "error: refusing to re-execute sbang to avoid infinite loop."
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Finally invoke the real shebang line
|
|
|
|
# ruby and perl need -x to ignore the first line of input (the sbang line)
|
|
|
|
#
|
|
|
|
if interpreter_is perl || interpreter_is ruby; then
|
|
|
|
# shellcheck disable=SC2086
|
2020-10-28 21:07:05 +00:00
|
|
|
$exec $shebang_line -x "$@"
|
2016-03-05 12:18:48 +00:00
|
|
|
else
|
2020-10-26 18:06:03 +00:00
|
|
|
# shellcheck disable=SC2086
|
2020-10-28 21:07:05 +00:00
|
|
|
$exec $shebang_line "$@"
|
2016-03-05 12:18:48 +00:00
|
|
|
fi
|