backquotes, system, shell and ruby

J

John Carter

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?

Because...

a) Ruby doesn't have a good syntax for invoking and dealing with
processes and pipes between processes.

b) Ruby doesn't have a built in understanding of ENV['PATH']

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.


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?


John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : (e-mail address removed)
New Zealand

A Million Monkeys can inflict worse things than just Shakespeare on
your system.
 
R

Ryan Pavlik

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?"

It's sh. Deal with it. ;-) It's not great, but it's not so bad,
either. I would, however, not mind having a ruby shell. But I also
don't expect to use ruby---which is designed to be suitable primarily
as a programming language---to *directly* fit the bill.
And that got me thinking.

Consider backquotes.
Why? Why does a scripting language like Ruby keep invoking an old and bad
scripting language call shell?

I'm not sure what you're getting at here. Yes, it ran a shell,
because that's what system() does. You can even do it in C, although
C doesn't use backticks as a shorthand.
Because...

a) Ruby doesn't have a good syntax for invoking and dealing with
processes and pipes between processes.

You mean like File.popen?
b) Ruby doesn't have a built in understanding of ENV['PATH']

The OS understands the path for you. Ruby doesn't need to.
c) Ruby doesn't have such a simple syntax for globbing (beyond
Dir['*.c'])

Ruby isn't a shell, either, and although it is a scripting language
(which explains the presence of ``), this doesn't automatically make
it suitable for a drop-in shell replacement.
Consider the "rename" facility that comes with perl these days.
Ooh! Looky! Nice! Wouldn't it be nice to have the power of ruby
intertwingled with the commandline.

At times I fire up irb to take care of similar complex tasks.
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?

What you need to do is simply write a shell that uses ruby instead of
its own sh-like syntax. Modifying ruby is not the answer. Using ruby
and a little readline loop with some decent parsing (calls to fork,
popen, etc.: process and IPC handling) is.

I must say I have wanted something like this for awhile. I even came
up with a really nice syntax for integrating shell commands and ruby,
although I forget off the top of my head what it was... it'd be
_fairly_ easy to do.

Just don't try to modify ruby to do it, because it's not the right
solution.
 
H

Harry Ohlsen

John said:
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?

I think it sits in the "it's the easiest thing to to do" basket.
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/' *

Something like that would be quite nice, since it's a pain in the butt to do with most shells ... strangely, this is one of the few things that DOS has done nicely for about ten years.

Of course, it's pretty easy to do in Ruby already (warning: totally untested) ...

Dir["*.bak"].each do |file|
File.rename file, file.sub(/\.bak$/, "")
end

or maybe

def rename(wildcard, &block)
Dir[wildcard].each do |file|
File.rename file, (yield file)
end
end

rename("*.bak") {|f| f.sub(/\.bak$/, "")}
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?

I guess it comes down to how much of the shell syntax you want to parse. While it's not hideously complex, sh/bash syntax is quite a funny grammar. I guess handling just globbing, pipes and redirection would be enough to make this useful, though.

The other issue, I would imagine, is *which* shell's syntax to use. I've never needed to know, so I've not looked, but I assume both system() and backticks just end up calling the C system() library routine, which means that the shell invoked is effectively user-defined.

Cheers,

Harry O.
 
S

Sean O'Dell

John said:
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
 
E

Eric Hodel

--cjNiBkmi8s9yAE0W
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
Consider backquotes.
=20
a =3D `wc *.c`
=20
What did that do? Same as open("|wc *.c").
=20
It ran bash!
=20
Yuck!
=20
system( "tar -xvzf foo.tgz foo")
=20
What did that do? It ran shell!
=20
Why? Why does a scripting language like Ruby keep invoking an old and bad
scripting language call shell?

Because that's what system(3) does, check the man page.

Perl does it, and if I had a Python installed, I bet python would do it
too. If you want it to not run in a shell, use fork and exec.

--=20
Eric Hodel - (e-mail address removed) - http://segment7.net
All messages signed with fingerprint:
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04


--cjNiBkmi8s9yAE0W
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2 (FreeBSD)

iD8DBQE/fQbUMypVHHlsnwQRAqWjAJ9DyyL833lzbfM4pesnCuZpNoItdQCg+idf
II0y/k9ARU3ny7SoapRpXDQ=
=MYvX
-----END PGP SIGNATURE-----

--cjNiBkmi8s9yAE0W--
 
D

Dave Brown

: 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!

So, er...

Give it a list instead!

irb(main):012:0> system("echo $PPID")
16554
=> true
irb(main):013:0> system("echo","$PPID")
$PPID
=> true

The second version has not been touched by a shell of any kind.
Cool, huh?

: Why? Why does a scripting language like Ruby keep invoking an old and bad
: scripting language call shell?
:
: Because...

....you keep telling it to!

"Doctor, it hurts when I do this!" "Well, stop doing that then."

--Dave
 
R

Robert Klemme

John Carter said:
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?

Because...

.... you did not invoke it with an array.
a) Ruby doesn't have a good syntax for invoking and dealing with
processes and pipes between processes.

b) Ruby doesn't have a built in understanding of ENV['PATH']

c) Ruby doesn't have such a simple syntax for globbing (beyond
Dir['*.c'])

???

ruby -e 'p Dir["/cygdrive/c/temp/ruby/*.{rb,bak}"]'
ruby -e 'p Dir["/cygdrive/c/temp/**.{rb,bak}"]'

That's quite powerful and simple.
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

ruby -e 'Dir["*.bak"].each {|f| File.rename(f, f.gsub(/\.bak$/, ""))}'
To translate uppercase names to lower, you'd use

rename 'y/A-Z/a-z/' *

ruby -e 'Dir["*"].each {|f| File.rename(f, f.upcase)}'
ruby -e 'Dir["*"].each {|f| File.rename(f, f.tr("a-z", "A-Z"))}'
Ooh! Looky! Nice! Wouldn't it be nice to have the power of ruby
intertwingled with the commandline.


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?

We could - but I wouldn't make this the default since every shell has it's
own pecularities (i.e. different syntax and built in commands. Why not
simply write a method that takes a string and returns an array processed
according to a particular shell convention? Then you can do

system( bashParse( "ls -lf *.bak" ) )

which is quite simple IMHO.

But I would leave in the default shell invocation because that gives most
flexibility.

Regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top