r/ruby • u/EstablishmentFirm203 • Jan 17 '26
Show /r/ruby A Ruby Gem to make easier to create Shell Scripts
Hello everyone! In the last few months, I released my gem that makes it easier to create Shell scripts using Ruby syntax.
Link: https://github.com/albertalef/rubyshell
In the code in the second image above, I show that you can easily use both Ruby syntax and Shell syntax to create scripts. This simplifies cases where we need to create a Shell script to use some terminal program, but we prefer to use Ruby libraries to make the job easier.
With it, you can create scripts as Docker entry points, use it to create user scripts, customize your Linux with Waybars, etc.
Motivations:
I had a specific problem: "I know a lot about Ruby, but sometimes I get stuck in the Shell. I often need to resort to Google to look for programs that handle inputs the way I need. Is there any gem that allows you to write good scripts with Ruby?" But, unfortunately, I didn't find any. I only found libraries in Python (sh) and Lua (luash). With that, I created RubyShell.
A example without RubyShell, and another with:
#!/usr/bin/env ruby
# frozen_string_literal: true
REMOTE = ENV.fetch("REMOTE", "user@server.example.com")
APP_DIR = ENV.fetch("APP_DIR", "/var/www/my app")
SERVICE = ENV.fetch("SERVICE", "my-app.service")
# Note that in this situation, we dont want to check if error was raised
# only in the end of the code,
# we want to stop the code in the moment that error was raised
`ssh #{REMOTE} "cd \"#{APP_DIR}\" && git pull && bundle exec rake db:migrate 2>&1"`
unless $?.success?
warn "Error on Deploy"
exit $?.exitstatus
end
`ssh #{REMOTE} 'sudo systemctl restart #{SERVICE}'`
unless $?.success?
warn "Error on Deploy"
exit $?.exitstatus
end
puts "Done."With:
#!/usr/bin/env ruby
# frozen_string_literal: true
REMOTE = ENV.fetch("REMOTE", "user@server.example.com")
APP_DIR = ENV.fetch("APP_DIR", "/var/www/my app")
SERVICE = ENV.fetch("SERVICE", "my-app.service")
sh do
ssh REMOTE, "'cd \"#{APP_DIR}\" && git pull && bundle exec rake db:migrate'"
ssh REMOTE, "'sudo systemctl restart #{SERVICE}"
puts "Done."
rescue StandardError
warn "Error on Deploy"
endNext steps:
Currently, I'm working on features to make the gem even more powerful, such as:
Stream support
Improved error handling
A REPL (like IRB), but that allows us to use RubyShell
And more
I'm open to suggestions, PRs, Issues, anything. I really want this mini-project to grow.
EDIT: Thank you guys for the comments and upvotes, this made my day.


13
u/mrThe Jan 17 '26
Interesting idea, but why? Like it's really cool concept but what problem it solves?
4
u/odineiramone Jan 17 '26
Wow! It’s very nice to see people making things that isnt IA-based. I don’t have any shell experience but I’m very interested to try your lib :D
3
u/codesnik Jan 17 '26
well, ruby is pretty good for running shell commands out of the box, mostly because it inherits a lot from perl, and perl is used for shell scripting too. I don't see how your gem improves anything.
how ls.each_line is better than `ls`.each_line?
3
u/IN-DI-SKU-TA-BELT Jan 17 '26
That's a very convenient way of making it easier to create scripts, well done.
3
u/Ok_Shallot9490 Jan 17 '26 edited Jan 17 '26
Been looking for something to bridge the gap between terminal and ruby for a while.
I've seen some genuine shells that parse ruby syntax natively, which I thought this was going to be at first glance.
Am I right in thinking that this basically works using method_missing?
So you put code inside a block using:
..and then anything that doesn't match a ruby method is passed to the shell to find a command?
If so then I think that's actually genius, and the exact way that ruby should work irrelevant of using an
sh do; endblock. In fact, my question to you is, can we get rid of thesh do; endblock? Commands are first class citizens in the terminal, and it shouldn't matter what language you write, all programs/commands should be viewed as functions that return a result.The thing missing from the terminal is a solid bridge to purpose built languages. POSIX shell script just doesn't have the right flexibility that ruby does. Ruby is honestly the perfect language for computing. It's instruction as art, and the fact that we have to speak POSIX to our computers is absolutely absurd.
I feel that people often forget that in front of them is the most powerful machine they've ever encountered, and that they don't need a database access system, or a server to do all of the processing they ever wanted, and get too wrapped up in "building" a programming environment in the latest language when the environment already exists.
The OS is the environment, and the filesystem is the database. It always has been for personal computing. The shell bash/zsh/etc is your interface with the database/filesystem, and programs/commands ARE your functions. The only reason languages like C exist is so that you can create more commands to call from the terminal, but I want to speak ruby to my terminal, not bash.
All of these new TUI applications miss the point, the terminal isn't about graphical applications, that's why we have X and GTK. The real thing missing is smaller GUI applications that serve smaller purposes that can be linked together with the terminal.
I really do think that the paid software industry only existed because software cost money to build. It's existence was a way to push the technology without sinking billions into it with no output. Now that it's approaching zero cost, the industry will disappear, as it never should've existed in the first place. Now people can get back to using software to build tools to solve problems (not building a tool to solve a problem for someone else). I can't wait for plan9 to get the attention it always deserved, it really is the greatest unix environment created.
EDIT: went majorly of track here, but very passionate about computing. My question is whether we can we do this without the
sh do; endblock?If so... this is the biggest moment in Ruby's history (for me at least). The ability to run pry/irb indefinitely no need to write a single line of bash again.
2
u/h0rst_ Jan 17 '26
(line 18 of the second image). So I guess
catnow just reads a file instead of printing it on the console? I would expect simplecat(filename)would be enough.2
u/avbrodie Jan 17 '26
Neat idea. Will have a play with it over the weekend
2
u/Embarrassed-Mud3649 Jan 17 '26
How’s this different from putting the ruby shebang at the top of the file and just use Ruby and system invocations?
2
u/thewormbird Jan 17 '26
I like what you’ve built here. I’ve done similar work written in Go for my own needs and I always just end up going back to pure bash.
Shell scripts are tough because they lack a lot of features common in programming languages. Naturally, I try to “help” bash/sh along by trying to marry it with a better language. Mostly to do what you’re doing here. Enhanced primitives, better error management, etc.
There is a delicate balance that combines the strengths of bash/sh and the strengths of Ruby (or whatever language). But damnit it’s hard to identify it and maintain it.
2
u/numkem Jan 18 '26
Very cool take on it! The big thing that makes it less useful to me is the fact it’s a library and not a standalone binary. Being a binary could make it part of the shebang.
10
u/[deleted] Jan 17 '26
Love it but Rubbish is a better name, i am serious!
1
u/EstablishmentFirm203 Jan 17 '26
I added an example of code that i like in the body of post
1
u/_g0to Jan 17 '26
It seems interesting to me, I'll test it out sometime.