2023-11-13
I wanted to write a script that could be executed by either
/bin/sh
or Ruby and successfully work in either case. I
couldn’t find a working example on the Internet or via GPT-4, so ended
up figuring this one out:
print () {
=begin
}
echo 'running as shell'
exit
=end
}
puts 'running as ruby'
This is slightly arcane so let’s walk through it from both perspectives.
/bin/sh
seesFirst, we’re defining a function called print
that takes
no arguments. If we would ever run it (we won’t), it would try to find
an execute a program named =begin
. Then, it just runs
echo 'running as shell'
and exits. Simple! The stuff
afterward is ignored because /bin/sh
doesn’t prospectively
parse ahead of the current statement.
This is a little weirder. First, we’re calling print
with no arguments, and a block. print
accepts a block, and
as far as I can tell just does nothing with it. When you call it with no
arguments, it just does nothing. So essentially this print
call is just a no-op.
=begin
and =end
are a very rarely used ruby
feature that demarcates block comments. So the whole shell bit in the
middle is a comment from ruby’s perspective. Let’s highlight this as
ruby to demonstrate:
print () {
=begin
}
echo 'running as shell'
exit
=end
}
puts 'running as ruby'
That makes things more clear. We’re just calling print with no arguments and a block (which gets ignored) containing a block comment. Then we run our ruby code that gets ignored by the shell.