Ruby:一种很棒的 shell 脚本语言
Ruby: A great language for shell scripts

原始链接: https://lucasoshiro.github.io/posts-en/2024-06-17-ruby-shellscript/

Ruby 是一种多功能且功能强大的编程语言,它超越了与 Rails 的流行联系。 尽管有些人可能会因为过去使用 Rails 的经验而对它不屑一顾,但 Ruby 提供了许多优点,特别是在编写复杂的 shell 脚本方面。 虽然 Bash 适合更简单的任务,但 Ruby 通过几个值得注意的特性提供了增强的功能: 1. **调用外部命令**:使用反引号 (```) 轻松调用外部命令,无需额外的库或技术,例如 `system()`、`popen()` 等。捕获变量内的输出以进行进一步处理。 2. **状态码**:通过特殊变量`$?.`访问上一个命令的退出状态 3. **Typing and Object-Oriented Programming**: Ruby follows Object-Oriented principles while providing support for typing, making it safer compared to Bash's reliance solely on strings。 4. **Functional Constructions**: Utilize map, filter (select), reduce, and other functional constructs as native methods, allowing for seamless chaining of operations。 5. **Regular Expression Matching**: Integrated regular expression matching within Ruby, enabling expressive pattern recognition。 6. **Easy Multithreading**: Simplify multithread creation and management using the Thread class。 7. **Built-In File and Directory Operations**: Leverage the File and Dir classes for handling various file and directory operations directly, reducing dependency on external modules。 考虑将 Ruby 作为实现复杂 shell 脚本的首选工具,与 Bash 等传统 shell 脚本解决方案相比,它提供增强的功能和更轻松的实现。

Ruby 是一种多功能编程语言,以其可读的语法和高级功能提供了传统 shell 脚本的替代方案。 Ruby 继承了 Perl 和 Unix 工具(如 sh、sed 和 awk)的一些功能,同时允许开发人员编写更简洁的代码,同时从一开始就确保干净的变量管理和数据处理。 其增量增长能力可以通过最少的设置和样板从单行平稳扩展到复杂的多文件项目。 然而,与常用的 Linux 发行版和 Bash 不同的是,Ruby 通常不与操作系统一起安装,它们是预先安装并准备好进行 shell 脚本编写的。 要求用户安装 Ruby 会增加一层复杂性,并可能引导他们编写成熟的应用程序而不是简单的 shell 脚本。 因此,使用 Ruby 的 shell 脚本可能会演变成难以管理且难以使用的代码库,特别是与在不断变化的环境下保持一致的稳定 shell 脚本相比。 虽然 Go 由于易于操作系统操作而在工具领域广受欢迎,但在 Ruby 和 Go 之间进行 shell 脚本编写的决定主要取决于可用性和便利性。 这两种语言在各自的领域都表现出色——Ruby 具有可读性和易于扩展性,而 Go 则具有强大的性能和系统管理中的低级控制。 最终,选择合适的语言取决于特定的要求、舒适度和上下文。
相关文章

原文

Intro

Ruby is so associated with its most famous framework, Rails, that many people forget how amazing this language is. I mean, I know a lot of people who says “I don’t like Ruby” and when I ask why, they say something about Rails. Personally, I consider Ruby one of my favorite programming languages, and the last time I touched any Rails code was 7 years ago…

So, if I don’t use Rails anymore, what I do with Ruby? Well, Ruby is a very rich and complete language, perhaps even more than its more famous relative, Python (sadly, I can’t say the same about its ecosystem…). And one of the things that I think that Ruby is better than Python is using it for writing shell scripts.

That is, most of the cases Bash for me is enough, but if the script starts to become complex, I switch to Ruby. Here I show the main features that might be interesting for this case of use.

Goals

Non-goals

  • Replace entirely Bash scripts by Ruby scripts.

Feature 1: calling external commands

The first thing that you expect of language for writing shell scripts is to call external commands. In Ruby, you do that using backticks (`):

That’s it! You don’t need system, popen or something like that, or import a library. And if you set that to a variable, you’ll have the output of the command:

Note: if you want to use system (e.g. if you want the output to be redirected to stdout instead of a string) or popen (if you want to read or write data from or to a subprocess), those are also available in Ruby!

Feature 2: status code

This is real quick: in Ruby, the variable $? contains the status code of the last executed command. So, it’s really close to Bash:

`true`
puts $? # 0

`false`
puts $? # 1

Feature 3: it’s a typed language

Ruby is not a statically typed language, but it has types. In fact, it is a object-oriented language, and it follow strictly the OOP paradigm (more than Python, in some aspects even more than Java!). Bash, on the other hand, everything is a string, and that leads to several safety issues…

total_lines = `wc -l my_file`.to_i # an int containing the number of lines of a file
half = total_lines.div 2           # integer division
puts `head -n #{half} my_file`     # print half of the file

Feature 4: functional constructions

Ruby implements map, select (filter), reduce, flat_map and other functional operations as methods. So, you can, for example, apply a map over a command output:

puts `ls`.lines.map { |name| name.strip.length } # prints the lengths of the filenames

Feature 5: regex matching

Regex is a type in Ruby, and operations using regex are built-in in the language. Look at this example, where we get the current git branch name calling git branch:

current_branch_regex = /^\* (\S+)/
output_lines = `git branch`.lines
output_lines.each do |line|
  if line =~ current_branch_regex # match the string with the regex
    puts $1                       # prints the match of the first group  
  end
end

Note for Git lovers: I know that I could do that only using git branch --show-current, but that was the first example that came in my mind to demonstrate the use of regex…

Feature 6: easy threads

If want to work with multiple threads, Ruby is perhaps the one of the easiest language to do it. Look:

thread = Thread.new do
  puts "I'm in a thread!"
end

puts "I'm outside a thread!"

thread.join

So, it can be useful for, for example, downloading several files at the same time:

(1..10).map do |i|                       # iterates from i=1 to i=10, inclusive
  Thread.new do
    `wget http://my_site.com/file_#{i}`  # you can use variables inside commands!  
  end
end.each { |thread| thread.join }        # do/end and curly braces have the same purpose!

Feature 7: builtin file and dir operations

In Ruby, all the file operations are methods of the File class and all the directory operations are methods of the Dir class, as it should be. In Python, for example, if you want to read a file you use open, but if you want to delete it you need to use os.remove, and os does a lot of other things that are not related to files.

So, in Ruby:

exists = File.exists? 'My File'           # methods that return booleans end in ?
file_content = File.open('My File').read
File.delete 'My File'                     # parentheses are optional if it's not ambiguous

Conclusion

I hope that after reading this short text you consider using Ruby as a replacement for complex shell scripts. I mean, I don’t expect that you drop Bash entirely, but consider using Ruby when things get complex. Of course, you can do that in Python, Perl, even JS, but, as my personal choice I think that Ruby is the most complete and easier Bash replacement for that!

If you find something wrong, or if you have any suggestion, please let me know here.

Update

This reached #1 on Hacker News! Not only that, but it started some interesting discussions in the comments. Thanks everyone!

联系我们 contact @ memedata.com