Bash and Zsh's HEREDOC seems to act like a file, instead of string, and if I hope to do something like
foo() {
ruby << 'EOF'
3.times do
puts "Ruby is getting the argument #{ARGV[0]}"
end
EOF
}
is there a way to pass in an argument to the Ruby program? It will be best not to interpolate the $1
into the Ruby code, so that's why I am using 'EOF'
instead of EOF
, as interpolating into the Ruby code can be messy.
There is one way to use the HEREDOC as a string, by the following method:
foo() {
ruby -e "$(cat << 'EOF'
3.times do
puts "Ruby is getting the argument #{ARGV[0]}"
end
EOF
)" $1
}
and it works (although a little bit hacky). But is there a way then to use the HEREDOC's usual way of treating it as a file and be able to supply an argument to Ruby?
Best Answer
On systems with
/dev/fd/n
, you can always do:Here using a fd above 2 so your
ruby
script can still use stdin/stdout/stderr unaffected.If your system is one of the rare few that still don't support
/dev/fd/n
, you can do:(where
ruby
itself interprets-
as meaning stdin).But that means that the
ruby
inline script's stdin is now that heredoc, so that script won't be able to query the user via the original stdin unless you provide that stream some other way.Heredoc is a feature that came with the Bourne shell in the late 70s. It's a redirection operator, it's meant do redirect some file descriptor (
0
aka stdin by default) to some fixed content. Originally, that was implemented via a temporary file, though some shells, including bash5.1+ use (sometimes) pipes instead.Also note that in
ruby -e code -- arbitrary-argument
, like insed -e code
orperl -e code
but unlike insh -c code
,python -c code
, you do need that--
to mark the end of options as otherwise ifarbitrary-argument
started with-
, it would be treated as an option toruby
.We don't need it in
ruby /dev/fd/3 arbitrary-argument
norruby - arbitrary-argument
as options are not expected after that non-option argument that is-
or/dev/fd/3
.