From: Sean O'Dell Date: 2003-10-03T13:28:12+09:00 Subject: Re: backquotes, system, shell and ruby John Carter wrote: > Somebody suggested I use zsh instead of bash for my commandline, so I > looked at it, looked at the syntax for tweaking the profile files, and > said... > "Yuck! Another badly designed syntax! Why can't I just use Ruby?" > > And that got me thinking. > > Consider backquotes. > > a = `wc *.c` > > What did that do? Same as open("|wc *.c"). > > It ran bash! > > Yuck! > > system( "tar -xvzf foo.tgz foo") > > What did that do? It ran shell! > > Why? Why does a scripting language like Ruby keep invoking an old and bad > scripting language call shell? A script language, if it wants to be portable, doesn't "blend" itself with unix shell programs. Ruby has pipes, sockets and other perfectly normal programatic ways to communicate between applications. > Because... > > a) Ruby doesn't have a good syntax for invoking and dealing with > processes and pipes between processes. It has the IO::pipe method which is pretty standard. You create a pair of pipes, then fork and exec whatever program you want to communicate with. > b) Ruby doesn't have a built in understanding of ENV['PATH'] Well, PATH isn't really for programming languages; it's a shell/os paradigm. Programs *can* make use of it, if they choose to, but I don't see that as being a languages' responsibility. It's there in the ENV hash; use it if you need it. Anyway, it would be pretty simple to implement, and I wouldn't be surprised if there isn't support for finding programs with it buried somewhere in one of the libraries distributed with it. > c) Ruby doesn't have such a simple syntax for globbing (beyond > Dir['*.c']) > > Consider the "rename" facility that comes with perl these days. > For example, to rename all files matching "*.bak" to strip the exten- > sion, you might say > > rename 's/\.bak$//' *.bak > > To translate uppercase names to lower, you'd use > > rename 'y/A-Z/a-z/' * > > Ooh! Looky! Nice! Wouldn't it be nice to have the power of ruby > intertwingled with the commandline. I would write: Dir["*.bak"].each{|f| File::rename(f, f.gsub(/\.bak$/, "")) } and: Dir["*"].each{|f| File::rename(f, f.gsub(/[a-z]/){|s| s.upcase}) } Wordy, but it should work just fine. Anyway, Ruby isn't a shell, it's a programming language. > Ruby does have Shell.rb, which takes us halfway there. (If it had > decent docs...) > > How hard would it be to extend the backtick syntax to be a pure ruby > thing. ie. So proc_exec doesn't invoke bash, but invokes Shell.rb? > > Hmm. Could we even do this entirely in UserLand? ie. Couldn't we > override proc_exec and replace it with ruby code that parses the > string, handles the redirects, variable interpolation quoting and > forks, then just directly execs the program without ever touching sh? I personally don't think it's Ruby's job to be more like a shell. Shells do that very well already. Besides, no matter how much you modified Ruby to make it more shell-like, you are always going to find things it won't do as well as a shell could, so you will drop out and ask the shell to do it. Using a programming language, as opposed to a shell, means that some things are easier to do, and some things are harder. But I don't think changing Ruby to make a specific group of tasks easier, when shells already do those tasks very well, is the answer. Sean O'Dell