我经常遇到这种情况:

  • GitBook 有 “server” 命令,例如 gitbook serve
  • Jekyll 有 “server” 命令,例如 jekyll serve
  • Rails 有 “server” 命令,例如 rails server

以上命令都不尽相同,每次打 “server” 命令之前都得想一会儿到底该使用哪个命令,少一点还好,但是一旦类似的命令多了容易搞错也不容易想起来,假如有一个 server 命令,可以自动选择合适的命令去执行就好了。

心动不如行动,下面是我用 Ruby 写的解决方案,若不喜欢用 Ruby,可用其它语言改写一下即可,思路是类似的。

#!/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}"

将以上文件命名为 server,并放到 bin 目录下,在给它加上可执行权限 chmod +x ./server,即可愉快使用了。

有一点需要注意的:执行命令使用 exec 比较合适,不要使用 system 等,如果使用 system,Ruby 进程并不会退出而是会等待 system 返回,而 server 命令不是立即返回的,所以用 system 不合适,Ruby 进程会一直等待,而 exec 是完全替换进程的,所以不存在这个问题。

以上程序还是不够智能,如果我想使某个目录下的所有子目录都执行相同的命令,岂不是要一个个子目录去设置,这显然是不合适的,所以继续给上面的程序加入正则匹配功能。

#!/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}"