Skip to content

Instantly share code, notes, and snippets.

@zealinux
Forked from gwerbin/shebang.zsh
Created January 16, 2017 13:53
Show Gist options
  • Save zealinux/64b4ccb8d0263bba3e89a57f1d07cd64 to your computer and use it in GitHub Desktop.
Save zealinux/64b4ccb8d0263bba3e89a57f1d07cd64 to your computer and use it in GitHub Desktop.
"Shebang" function for Zsh
# shebang [-iv] [-t interpreter] [-I extension] [-J [extension]] [filename]
#
# If no filename is given, print a shebang. If a filename is given, append a shebang to the file and print its contents. If a filename is given and the -I or -J options are specified, append a shebang to the file in place.
#
# OPTIONS
# -i
# Interactive mode; ask for confirmation first.
# -I
# Modify "filename" in place (as in `sed -i`) using specified extension. Extension is mandatory.
# -J
# Same as -I, but extension is mandatory only if the string "gsed" cannot be found in the output of `which sed`. Overridden by -I.
# -t
# Specify an interpreter, e.g. `shebang -t zsh` produces "#!/usr/bin/env zsh"
# -v
# Print (to stderr) the interpreter being used.
shebang () {
local interpreter
local inplace
local inplace2
local verbose
local interactive
local input_shebang
local shebang
local continue
local sed_command
local gsed_avail
zparseopts -D t:=interpreter I:=inplace J::=inplace2 v=verbose -i=interactive
(( $? )) && return 1
if [[ -n $1 ]]; then
input_shebang=$(sed -n '1 { /^#!/ p; }' "$1")
if (( $? )); then
echo "Unable to read $1." >&2
return 1
fi
if [[ -n "$input_shebang" ]]; then
echo "$1 already has a shebang." >&2
return 1
fi
fi
if [[ (-z "$interpreter") && (-z "$1") ]]; then
echo "The -t option is mandatory if no argument is supplied." >&2
return 1
fi
if [[ (-z "$interpreter") && (-n "$1") ]]; then
interpreter=$(filename=$(basename "$1"); [[ "$filename" = *.* ]] && echo "${filename##*.}" || echo '') # grab extension
interpreter=${interpreter:#(* *|* | *)} # "extensions" with whitespace probably aren't legit
interpreter=${interpreter:-sh} # assume sh if no extension and no -t option
else
interpreter="$interpreter[2]"
fi
shebang="#!/usr/bin/env $interpreter"
if [[ -n $verbose ]]; then
echo "Using interpreter '$interpreter'" >&2
fi
if [[ -n $interactive ]]; then
read -q "continue?Shebang will be '$shebang'. Ok? y/n: "
[[ $continue == n ]] && return 1
fi
if [[ -z "$1" ]]; then
echo $shebang
else
gsed_avail=$(command which -s gsed && echo 1)
echo $gsed_avail
if [[ -n $gsed_avail ]]; then
sed_command="1 i\\$shebang\n"
if [[ -n $inplace ]]; then
gsed "${inplace/-I/-i}" "$sed_command" "$1"
elif [[ -n $inplace2 ]]; then
gsed "${inplace2/-J/-i}" "$sed_command" "$1"
else
gsed "$sed_command" "$1"
fi
else
sed_command='1 i\
REPLACEME\n' # need to use single quotes to preserve the line break
sed_command=${sed_command/REPLACEME/$shebang} # work around the single quotes
if [[ -n $inplace ]]; then
sed "${inplace/-I/-i}" "$sed_command" "$1"
elif [[ (-n $inplace2) && (-z ${inplace2#-J}) ]]; then
echo "'-J' was given without an argument, but 'gsed' is unavailable. Specify an explicit extension or use -I."
elif [[ -n ${inplace2#-J} ]]; then
sed "${inplace2/-J/-i}" "$sed_command" "$1"
else
sed "$sed_command" "$1"
fi
fi
fi
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment