I often encounter situations like this:

  • GitBook has a “server” command, for example, gitbook serve.
  • Jekyll has a “server” command, for example, jekyll serve.
  • Rails has a “server” command, for example, rails server.

The commands above are not exactly the same, and every time before I type the “server” command, I have to think for a while about which command to use. It’s okay if there are only a few, but once there are many similar commands, it’s easy to get confused and hard to remember. It would be great if there was a server command that could automatically choose the appropriate command to execute.

Action speaks louder than words. Below is a solution I wrote in Ruby. If you don’t like using Ruby, you can rewrite it in another language; the idea is similar.

#!/usr/bin/env ruby

dir_commands = {
  "/Users/mwum/Gitbook/Ruby"            => "gitbook serve --port 4006",
  "/Users/mwum/dx"                      => "jekyll serve -w",
  "/Users/mwum/Code/Rails/chat-system"  => "bundle exec rails server"
}

dir_commands.each do |dir, command|
  if Dir.pwd == dir
    exec command
  end
end

puts "#{File.basename(__FILE__)}: no command defined for current directory: #{Dir.pwd}"

Name the file above as “server” and place it in the bin directory. Make it executable with chmod +x ./server, and you can use it happily.

One thing to note: It is more appropriate to use exec to execute commands, not system or others. If you use system, the Ruby process does not exit but waits for system to return. Since the “server” command does not return immediately, using system is not appropriate; the Ruby process will wait indefinitely. However, exec completely replaces the process, so this problem does not occur.

The program above is still not smart enough. If I want all subdirectories under a certain directory to execute the same command, it’s obviously not suitable to set each subdirectory individually. Therefore, continue to add regular expression matching functionality to the program above.

#!/usr/bin/env ruby

dir_commands = {
  %r{/Users/mwum/Gitbook/*}         => "gitbook serve --port 4006",
  "/Users/mwum/dx"                  => "jekyll serve -w",
  %r{/Users/mwum/Code/Rails/*}      => "bundle exec rails server"
}

dir_commands.each do |dir, command|
  case dir
  when String
    if Dir.pwd == dir
      puts "Execute command: #{command}"
      exec command
    end
  when Regexp
    if Dir.pwd =~ dir
      puts "Execute command: #{command}"
      exec command
    end
  else
    puts "This dir class is not supported: #{dir.class}"
    exit
  end
end

puts "#{File.basename(__FILE__)}: no command defined for current directory: #{Dir.pwd}"