(and also thank you j-p-hutchins for fixing the error with true)
Yes. Not Just Possible, But Reliable, Minimal, Easy to Edit and Fast
A mere 41 chars, the rest is actual code.
Edit (several years later), 15 chars, we can do it in 15! I don't yet have the time to update the whole breakdown below (which is still valid) but if you really like code-golfing here's the shorter version:
#!/bin/sh
? "\"<#" 2>&-
echo "Hi Shell"
exit #>
echo "Hi Powershell"
(For this one, the key is that \" is not an escape in powershell, ? is a command on in powershell, and 2>&- turns off stderr rather than 2>/dev/null redirecting it)
TLDR: Copy Paste
Save this as your_thing.ps1 for it to run as powershell on Windows and run as shell on all other operating systems.
#!/usr/bin/env sh
echo --% >/dev/null;: ' | out-null
<#'
#
# sh part
#
echo "hello from bash/dash/zsh"
echo "do whatver you want just dont use #> directly"
echo "e.g. do #""> or something similar"
# end bash part
exit #>
#
# powershell part
#
echo "hello from powershell"
echo "you literally don't have to escape anything here"
How does it work? (its a simple idea)
- We want to start a multi-line comment in powershell without causing an error in bash/shell.
- Powershell has multi-line comments
<# but as-is that syntax will cause problems in bash/shell languages. We need to use a string like "<#" for bash. New problem: we need it to NOT be a string in powershell.
- Powershell has a really werid "stop-parsing" arg
--% . That special arg lets us write a single quote without starting a string. E.g.
echo --% ' blah ' will print out ' blah ' in powershell, but in bash it will print out --% blah
- We need a command in order to use powershell's stop-parsing-args. Lucky for us both powershell and bash have an
echo command
- So, in bash we echo a string with
<#, but powershell the same code finishes the echo command then starts a multi-line comment
- Finally we add
>/dev/null to bash so that it doesn't print out --% every time, and we add | out-null so that powershell doesn't print out >/dev/null;: ' every time.
- Unlike powershell, bash doesn't parse whole files, it only parses one line at a time as-needed. If we put an
exit command before ending the powershell comment, bash will never read past it.
The syntax highlighting tells the story more visually
Powershell Highlighting
All the green stuff is ignored by powershell (comments)
The gray --% is special
The | out-null is special
The white parts are just string-arguments without quotes
(even the single quote is equivlent to "'")
The <# is the start of a multi-line comment

Bash Highlighting
For bash its totally different.
Lime green + underline are the commands.
The --% isn't special, its just an argument
But the ; is special
The purple is output-redirection
Then : is just the standard "do nothing" shell command
Then the ' starts a string argument that ends on the next line

Caveats?
Almost none. Powershell legitimately has no downside. The Bash caveats are easy to fix, and are exceedingly rare. Even better, its not just bash, its POSIX. It works with almost all linux shells.
- If you need #> in a bash string, you'll need to escape it somehow.
changing "#>" to "#"">"
or from ' blah #> ' to ' blah #''> '.
- If you have a comment
#> and for some reason you CANNOT change that comment (this is what I mean by exceedingly rare), you can actually just use #>, you just have to add re-add those first two lines (eg true --% etc) right after your #> comment
- One even more exceedingly rare case is where you are using the
# to remove parts of a string (I bet most don't even know this is a bash feature). Example code below
https://man7.org/linux/man-pages/man1/bash.1.html#EXPANSION
var1=">blah"
echo ${var1#>}
# ^ removes the > from var1
To fix this one, well there are alternative ways of removeing chars from the begining of a string, use them instead.
wgetbecause-Ois ambiguous between-OutputFile,-OutputVariableand-OutputBuffer. (Unless you have installed wget.exe for Windows and removed the wget alias, but that's not default, so you should say if you have).