@ -1,4 +1,4 @@
: "punk MULTISHELL - shebangless polyglot for Tcl Perl sh bash cmd pwsh powershell" + "[rename set S;proc Hide shell_not_supported {proc $shell_not_supported args {}};Hide :]" + "\$(function : {<#pwsh#>})" + "perlhide" + qw^
: "punk MULTISHELL - shebangless polyglot for Tcl Perl sh zsh/ bash cmd pwsh powershell" + "[rename set S;proc Hide shell_not_supported {proc $shell_not_supported args {}};Hide :]" + "\$(function : {<#pwsh#>})" + "perlhide" + qw^
set -- " $@ " " a=[Hide <#;Hide set;S 1 list] " ; set -- : " $@ " ;$1 = @'
: heredoc1 - hide from powershell using @ and squote above. close sqote for unix shells + ' \
: .bat/.cmd launch section, leading colon hides from cmd, trailing slash hides next line from tcl + \
@ -13,7 +13,7 @@ set -- "$@" "a=[Hide <#;Hide set;S 1 list]"; set -- : "$@";$1 = @'
: Continuation char at end of this line and rem with curly-braces used to exlude Tcl from the whole cmd block \
: {
@ REM ############################################################################################################################
@ REM THIS IS A POLYGLOT SCRIPT - supporting payloads in Tcl, bash, (some sh ) and/or powershelll (powershell.exe or pwsh.exe)
@ REM THIS IS A POLYGLOT SCRIPT - supporting payloads in Tcl, zsh, bash, (sh diversion ) and/or powershelll (powershell.exe or pwsh.exe)
@ REM It should remain portable between unix-like OSes & windows if the proper structure is maintained.
@ REM ############################################################################################################################
@ rem -------------------------------------------------------------------------------------------------------------------------------
@ -266,7 +266,8 @@ set ^"endlocal=for %%# in (1 2) do if %%#==2 (%\n%
set " param= %% L "
@ REM @echo ######### %%L
@ rem call :buildcmdline newcommandline param "{" "}"
call : buildcmdline newcommandline param ' ' %= cmd.exe /c powershell % =
@ rem call :buildcmdline newcommandline param ' ' %= cmd.exe /c powershell ... -c %=
call : buildcmdline newcommandline param %= cmd.exe /c powershell ... -f % =
@ rem @echo .
)
) ELSE (
@ -303,6 +304,7 @@ SETLOCAL EnableDelayedExpansion
@ IF " !selected_shelltype_trimmed! " == " pwsh " (
REM pwsh vs powershell hasn't been tested because we didn't need to copy cmd to ps1 this time
REM test availability of preferred option of powershell7+ pwsh
REM when run without cmd.exe - pwsh will receive the semicolon (for cmd.exe unquoted semicolon and comma are separators that aren't seen in positional arguments)
pwsh -nop -nol -c set-executionpolicy -Scope Process Unrestricted 2 > NUL; write-host " statusmessage: pwsh-found " > NUL
SET pwshtest_exitcode = !errorlevel!
REM ECHO pwshtest_exitcode !pwshtest_exitcode!
@ -310,18 +312,18 @@ SETLOCAL EnableDelayedExpansion
IF !pwshtest_exitcode! == 0 (
@ rem pwsh -nop -nol -c set-executionpolicy -Scope Process Unrestricted; "%scriptrootname%.ps1" %arglist%
@ rem pwsh -nop -nol -c set-executionpolicy -Scope Process Unrestricted
cmd /c pwsh -nop -nol -ExecutionPolicy bypass -c " %scriptrootname% .ps1 " !newcommandline!
cmd /c pwsh -nop -nol -ExecutionPolicy bypass -f " %scriptrootname% .ps1 " !newcommandline!
SET task_exitcode = !errorlevel!
) ELSE (
REM TODO prompt user with option to call script to install pwsh using winget
@ rem powershell -nop -nol -ExecutionPolicy Bypass -c "%scriptrootname%.ps1" %arglist%
cmd /c powershell -nop -nol -ExecutionPolicy Bypass -c " %scriptrootname% .ps1 " !newcommandline!
cmd /c powershell -nop -nol -ExecutionPolicy Bypass -f " %scriptrootname% .ps1 " !newcommandline!
SET task_exitcode = !errorlevel!
)
) ELSE (
IF " !selected_shelltype_trimmed! " == " powershell " (
@ rem powershell -nop -nol -ExecutionPolicy Bypass -c "%scriptrootname%.ps1" %arglist%
cmd /c powershell -nop -nol -ExecutionPolicy Bypass -c " %scriptrootname% .ps1 " !newcommandline!
cmd /c powershell -nop -nol -ExecutionPolicy Bypass -f " %scriptrootname% .ps1 " !newcommandline!
SET task_exitcode = !errorlevel!
) ELSE (
IF " !selected_shelltype_trimmed! " == " wslbash " (
@ -373,6 +375,7 @@ endlocal & set "%~3=%rtn%"
exit /b
%= ---------------------------------------------------------------------- =%
@ REM padding
: buildcmdline cmdlinevar paramvar wrapA wrapB
%= quoting for cmd.exe /c pwsh -nop !args! =%
@ SETLOCAL EnableDelayedExpansion
@ -650,6 +653,8 @@ do if not defined param1 set %%~"param1=%2%%~"
@ REM boundary padding
@ REM boundary padding
@ REM boundary padding
@ REM boundary padding
@ REM boundary padding
: stringTrimTrailingUnderscores
@ SETLOCAL
@ SET " rtrn= %~2 "
@ -842,16 +847,6 @@ namespace eval ::punk::multishell {
puts stderr " No tcl code for this script. Try another program such as zsh or bash or perl "
#< /tcl-payload>
#< tcl-pre-launch-subprocess>
#< /tcl-pre-launch-subprocess>
#< tcl-launch-subprocess>
#< /tcl-launch-subprocess>
#< tcl-post-launch-subprocess>
#< /tcl-post-launch-subprocess>
# -- --- --- --- --- --- --- --- --- --- --- ---
# -- Best practice is to always return or exit above, or just by leaving the below defaults in place.
@ -872,28 +867,61 @@ if {[::punk::multishell::is_main]} {
HEREDOC1B_HIDE_FROM_BASH_AND_SH
# Be wary of any non-trivial sed/awk etc - can be brittle to maintain across linux,freebsd,macosx due to differing implementations \
echo " var0: $0 @: $@ "
# echo " script: `echo $0 | sed 's/ ^ -//'` "
# use oldschool backticks and sed - lowest common denominator \
# echo " shell: " `ps -p $$ | awk '$1 != " PID " {print $(NF)}' | tr -d '()' | sed -E 's/^. *\/| ^- //'`
# zsh diversion \
# if [[ " $argv[*] " != " [*] " ]]; then /usr/bin/env bash " $0 " " ${argv[@]:2:$((${#argv[@]}-2))} " ; exit $?; fi
# \
ps_shellname=`ps -p $$ | awk '$1 != " PID " {print $(NF)}' | tr -d '()' | sed -E 's/^. *\/| ^- //'`
# \
echo " shell from ps: $ps_shellname argc: ${#@} inner: ${@:2:$((${#@}-2))} "
# non-bash-like diversion \
if [[ " $ p s _ s h e l l n a m e " ! = " b a s h " & & " $ p s _ s h e l l n a m e " ! = " z s h " ] ] ; t h e n / u s r / b i n / e n v b a s h " $ 0 " " $ { @ : 2 : $ ( ( $ { # @ } - 2 ) ) } " ; e x i t $ ? ; f i
# sh/bash (or zsh?) \
shift && set -- " ${@:1:$((${#@}-1))} "
# \
#echo " shell: " `ps -o args= $$ | sed -E 's/^. *\/| ^- //' | awk '{print $1}'`
echo " shell from ps: $ps_shellname "
# \
echo " args: $@ "
# ------------------------------------------------------------------------------
# -- This if block wraps posix sh diversion section - only needed if Tcl didn't exit or return above.
if false== false # else {
then
: #
# https://gist.github.com/fcard/e26c5a1f7c8b0674c17c7554fb0cd35c0 (MIT lic)
# https://stackoverflow.com/questions/63864755/remove-last-argument-in-shell-script-posix
# posix compliant pop
pop() {
__pop_n=$(($1 - ${2:-1}))
if [ - n " $ Z S H _ V E R S I O N " - o - n " $ B A S H _ V E R S I O N " ] ; t h e n
POP_EXPR='set -- " ${@:1:'$__pop_n'} " '
elif [ $__pop_n -ge 500 ]; then
POP_EXPR=" set -- $(seq -s " " 1 $__pop_n | sed 's/[0-9]\+/ " ${\0}" /g') "
else
__pop_index=0
__pop_arguments=" "
while [ $__pop_index -lt $__pop_n ]; do
__pop_index=$((__pop_index+1))
__pop_arguments=" $__pop_arguments \ " \${$__pop_index}\" "
done
POP_EXPR=" set -- $__pop_arguments "
fi
}
# ------------------------------------------------------------------------------
# non-bash-like posix diversion \
if [ " $ p s _ s h e l l n a m e " ! = " b a s h " ] & & [ " $ p s _ s h e l l n a m e " ! = " z s h " ] ; t h e n
shift
pop $#
eval " $POP_EXPR "
echo " divert to bash $0 $@ "
/usr/bin/env bash " $0 " " $@ "
exit $?
fi
# close false==false block
fi
# close tcl wrap }
# ------------------------------------------------------
# -- This if block only needed if Tcl didn't exit or return above.
# -- This if block wraps whole zsh/bash and perl sections - only needed if Tcl didn't exit or return above.
if false== false # else {
then
: #
# zsh/bash \
shift && set -- " ${@:1:$((${#@}-1))} "
# ## ### ### ### ### ### ### ### ### ### ### ### ### ###
# -- sh/bash script section
# -- leave as is if all that is required is launching the Tcl payload"
@ -905,7 +933,7 @@ if false==false # else {
# ## ### ### ### ### ### ### ### ### ### ### ### ### ###
plat=$(uname -s) #platform/system
if [[ " $ p l a t " = " L i n u x " * ] ] ; t h e n
if [[ " $ p l a t " == " Linux " * ]]; then
os=" linux "
elif [[ " $plat " == " Darwin " * ]]; then
os=" macosx "
@ -917,11 +945,11 @@ elif [[ "$plat" == "NetBSD"* ]]; then
os=" netbsd "
elif [[ " $plat " == " OpenBSD " * ]]; then
os=" openbsd "
elif [[ " $plat " = " MINGW32 " * ]]; then
elif [[ " $plat " == " MINGW32 " * ]]; then
os=" win32 "
elif [[ " $plat " = " MINGW64 " * ]]; then
elif [[ " $plat " == " MINGW64 " * ]]; then
os=" win32 "
elif [[ " $plat " = " CYGWIN_NT " * ]]; then
elif [[ " $plat " == " CYGWIN_NT " * ]]; then
os=" win32 "
elif [[ " $plat " == " MSYS_NT " * ]]; then
#review..
@ -967,34 +995,34 @@ for ln in "${arr_oslines[@]}"; do
pathraw=" ${splitln %% \ " *}" #take everything before the quote - use %% to get longest match
#remove trailing underscores (% means must match at end)
nextshellpath=" ${pathraw/ % _*/} "
echo " nextshellpath: $nextshellpath "
# echo " nextshellpath: $nextshellpath "
elif [[ " $ln " == *" nextshelltype " * ]]; then
splitln=" ${ln#*=} "
typeraw=" ${splitln %% \ " *}"
nextshelltype=" ${typeraw/ % _*/} "
echo " nextshelltype: $nextshelltype "
# echo " nextshelltype: $nextshelltype "
fi
done
exitcode=0
#-- sh/bash launches nextscript here instead of shebang line at top
if [[ " $ n e x t s h e l l t y p e " ! = " b a s h " & & " $ n e x t s h e l l t y p e " ! = " n o n e " ] ] ; t h e n
echo bash launching subshell of type: $nextshelltype shellpath: $nextshellpath on " $0 " with args " $@ "
echo zsh/ bash launching subshell of type: $nextshelltype shellpath: $nextshellpath on " $0 " with args " $@ "
#e.g /usr/bin/env tclsh " $0 " " $@ "
${nextshellpath} " $0 " " $@ "
exitcode=$?
#echo " sh/bash reporting exitcode: ${exitcode} "
#echo " z sh/bash reporting exitcode: ${exitcode}"
exit $exitcode
#-- override exitcode example
#exit 66
else
#already in bash - don't launch another process or we would loop
#echo " bash payload "
#echo " zsh/ bash payload"
:
fi
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---begin sh Payload
#printf " start of bash or sh code "
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---begin z sh Payload
#printf " start of bash or z sh code "
#< shell-payload>
@ -1090,29 +1118,9 @@ cd $launchdir #restore original CWD
#< /shell-payload>
#< shell-pre-launch-subprocess>
#< /shell-pre-launch-subprocess>
# -- --- --- --- --- --- --- ---
#< shell-launch-subprocess>
#-- sh/bash launches Tcl here instead of shebang line at top
#-- use exec to use exitcode (if any) directly from the tcl script
#exec /usr/bin/env tclsh " $0 " " $@ "
#-- alternative - can run sh/bash script after the tcl call.
#/usr/bin/env tclsh " $0 " " $@ "
#exitcode=$?
#echo " sh/bash reporting tcl exitcode: ${exitcode} "
#-- override exitcode example
#exit 66
#< /shell-launch-subprocess>
# -- --- --- --- --- --- --- ---
#< shell-post-launch-subprocess>
#< /shell-post-launch-subprocess>
#printf " sh/bash done \n "
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---end sh Payload
#printf " zsh/bash done \n "
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---end zsh Payload
#------------------------------------------------------
fi
exit ${exitcode}
@ -1148,7 +1156,6 @@ print "os $os\n";
# -- --- ---
my $i =1;
foreach my $a(@ARGV) {
print " Arg # $i: $a\n " ;
@ -1158,21 +1165,11 @@ foreach my $a(@ARGV) {
print STDERR " No perl code for this script. Try another program such as tcl or bash " ;
#< /perl-payload>
#< perl-pre-launch-subprocess>
#< /perl-pre-launch-subprocess>
# -- --- --- --- --- --- --- ---
#< perl-launch-subprocess>
#$exit_code=system(" tclsh " , $scriptname, @ARGV);
#print " perl reporting tcl exitcode: $exit_code " ;
#< /perl-launch-subprocess>
# -- --- --- --- --- --- --- ---
#< perl-post-launch-subprocess>
#< /perl-post-launch-subprocess>
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---end perl Payload
exit $exit_code;
@ -1540,20 +1537,6 @@ write-host "`e[92m getpunk done `e[m"
#< /powershell-payload>
#< powershell-pre-launch-subprocess>
#< /powershell-pre-launch-subprocess>
# -- --- --- --- --- --- --- ---
#< powershell-launch-subprocess>
#tclsh $scriptname $args
#" powershell reporting exitcode: {0} " -f $LASTEXITCODE | write-host
#< /powershell-launch-subprocess>
# -- --- --- --- --- --- --- ---
#< powershell-post-launch-subprocess>
#< /powershell-post-launch-subprocess>
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---end powershell Payload
Exit $LASTEXITCODE