| 
									
										
										
										
											2020-10-26 11:06:03 -07:00
										 |  |  | #!/bin/sh | 
					
						
							| 
									
										
										
										
											2016-05-11 21:22:25 -07:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2021-04-22 22:23:09 -07:00
										 |  |  | # Copyright 2013-2021 Lawrence Livermore National Security, LLC and other | 
					
						
							| 
									
										
										
										
											2020-10-28 14:07:05 -07:00
										 |  |  | # sbang project developers. See the top-level COPYRIGHT file for details. | 
					
						
							| 
									
										
										
										
											2016-05-11 21:22:25 -07:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2018-10-07 13:52:23 -07:00
										 |  |  | # SPDX-License-Identifier: (Apache-2.0 OR MIT) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-05 04:18:48 -08:00
										 |  |  | # | 
					
						
							|  |  |  | # `sbang`: Run scripts with long shebang lines. | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											2020-10-26 11:06:03 -07: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 14:07:05 -07:00
										 |  |  | # To use, put the long shebang on the second line of your script, and | 
					
						
							|  |  |  | # make sbang the interpreter, like this: | 
					
						
							| 
									
										
										
										
											2016-03-05 04:18:48 -08:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2020-10-28 14:07:05 -07:00
										 |  |  | #     #!/bin/sh /path/to/sbang | 
					
						
							|  |  |  | #     #!/long/path/to/real/interpreter with arguments | 
					
						
							| 
									
										
										
										
											2016-03-05 04:18:48 -08:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2020-10-28 14:07:05 -07:00
										 |  |  | # `sbang` will run the real interpreter with the script as its argument. | 
					
						
							| 
									
										
										
										
											2016-03-05 04:18:48 -08:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2020-10-28 14:07:05 -07:00
										 |  |  | # See https://github.com/spack/sbang for more details. | 
					
						
							| 
									
										
										
										
											2016-03-05 04:18:48 -08:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2020-10-26 11:06:03 -07: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 04:18:48 -08:00
										 |  |  | # First argument is the script we want to actually run. | 
					
						
							|  |  |  | script="$1" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-26 11:06:03 -07: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 04:18:48 -08:00
										 |  |  | # Search the first two lines of script for interpreters. | 
					
						
							|  |  |  | lines=0 | 
					
						
							| 
									
										
										
										
											2020-10-26 11:06:03 -07: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 04:18:48 -08:00
										 |  |  |     fi | 
					
						
							|  |  |  |     lines=$((lines+1)) | 
					
						
							|  |  |  | done < "$script" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-26 11:06:03 -07:00
										 |  |  | # error if we did not find any interpreter | 
					
						
							| 
									
										
										
										
											2020-10-28 14:07:05 -07:00
										 |  |  | if [ -z "$shebang_line"  ]; then | 
					
						
							| 
									
										
										
										
											2020-10-26 11:06:03 -07:00
										 |  |  |     die "error: sbang found no interpreter in $script" | 
					
						
							|  |  |  | fi | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-28 14:07:05 -07:00
										 |  |  | # parse out the interpreter and first argument | 
					
						
							|  |  |  | IFS=' ' read -r interpreter arg1 rest <<EOF | 
					
						
							|  |  |  | $shebang_line | 
					
						
							|  |  |  | EOF | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-26 11:06:03 -07: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 09:43:47 +02:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2020-10-26 11:06:03 -07:00
										 |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2016-09-22 09:43:47 +02:00
										 |  |  |     fi | 
					
						
							| 
									
										
										
										
											2020-10-26 11:06:03 -07: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 14:07:05 -07:00
										 |  |  |     $exec $shebang_line -x "$@" | 
					
						
							| 
									
										
										
										
											2016-03-05 04:18:48 -08:00
										 |  |  | else | 
					
						
							| 
									
										
										
										
											2020-10-26 11:06:03 -07:00
										 |  |  |     # shellcheck disable=SC2086 | 
					
						
							| 
									
										
										
										
											2020-10-28 14:07:05 -07:00
										 |  |  |     $exec $shebang_line "$@" | 
					
						
							| 
									
										
										
										
											2016-03-05 04:18:48 -08:00
										 |  |  | fi |