Newbie wondering about command line arguments

P

Paul Emmons

I'm experimenting with writing a text filter, as a learning
experience.

Right now, I want the program to:
* work as a pure filter if there are no command-line arguments
* use the argument as an input file, send output to STOUT if there is
one argument
* If there are more than one argument, use the last argument as
an output file name and the others as input file names.

My question is not how to get my program to do this. It is doing it
exactly as I wanted, like a mind reader. My question is, how is it so
smart? I expect I'll have problems later on if I don't really
understand what is happening.

I have read that unless somehow told otherwise, a Ruby program uses
the command-line arguments as input file names and reads them one
after the other as though they came from STDIN. If I have used the
last argument as an output file name, why doesn't it run into trouble
when it comes to this argument and tries to use it as in input file?

And how, in general, do I make sure that a Ruby script does not try to
use an argument as an input file name if I want it to mean something
else?

Scratching my head (with delight for a change).

Thank you for any help.

(This is my program so far. :)

#!/usr/bin/env ruby
# Reverses characters in every line of a file

if STDIN.tty?
puts "No. of args = #{ARGV.size}"
ARGV.each { |a| puts "Arg = #{a}" }
if ARGV.size>1
$stdout=File.new(ARGV[ARGV.size-1], "w")
end
end

while line = gets
line.chomp!
puts line.reverse
end
 
J

Joel VanderWerf

Paul said:
And how, in general, do I make sure that a Ruby script does not try to
use an argument as an input file name if I want it to mean something
else?

You can modify ARGV.

$ cat >arg1
ARG1
$ cat >arg2
ARG2
$ ruby -e 'puts ARGF.read' arg1 arg2
ARG1
ARG2
$ ruby -e 'ARGV.pop; puts ARGF.read' arg1 arg2
ARG1

Note that ARGF.read is the same as calling Kernel#gets, except that it
slurps the whole string (and I like it because it's a bit more explicit).
 
R

Robert Klemme

Paul Emmons said:
I'm experimenting with writing a text filter, as a learning
experience.

Right now, I want the program to:
* work as a pure filter if there are no command-line arguments
* use the argument as an input file, send output to STOUT if there is
one argument
* If there are more than one argument, use the last argument as
an output file name and the others as input file names.

My question is not how to get my program to do this. It is doing it
exactly as I wanted, like a mind reader. My question is, how is it so
smart? I expect I'll have problems later on if I don't really
understand what is happening.

I have read that unless somehow told otherwise, a Ruby program uses
the command-line arguments as input file names and reads them one
after the other as though they came from STDIN. If I have used the
last argument as an output file name, why doesn't it run into trouble
when it comes to this argument and tries to use it as in input file?

And how, in general, do I make sure that a Ruby script does not try to
use an argument as an input file name if I want it to mean something
else?

Scratching my head (with delight for a change).

Thank you for any help.

(This is my program so far. :)

#!/usr/bin/env ruby
# Reverses characters in every line of a file

if STDIN.tty?
puts "No. of args = #{ARGV.size}"
ARGV.each { |a| puts "Arg = #{a}" }
if ARGV.size>1
$stdout=File.new(ARGV[ARGV.size-1], "w")
end
end

#!/usr/bin/ruby

out = nil

case ARGV.size
when 0, 1
out = $stdout
else
out = File.open( ARGV.slice!(-1,1)[0], "w" )
end

begin
while line = gets
line.chomp!
out.puts line.reverse
end
ensure
out.close unless out.equal? $stdout
end

robert
 
R

Relm

I have read that unless somehow told otherwise, a Ruby program uses
the command-line arguments as input file names and reads them one
after the other as though they came from STDIN. If I have used the
last argument as an output file name, why doesn't it run into trouble
when it comes to this argument and tries to use it as in input file?

If you are only testing with small input files, then the last input file
may well be empty when you try to read from it.
#!/usr/bin/env ruby
# Reverses characters in every line of a file

if STDIN.tty?
puts "No. of args = #{ARGV.size}"
ARGV.each { |a| puts "Arg = #{a}" }
if ARGV.size>1
$stdout=File.new(ARGV[ARGV.size-1], "w")

This truncates the last file to zero bytes.
end
end

while line = gets
line.chomp!
puts line.reverse

This puts a reversed line into a buffer. It does not write anything to
the last file until the buffer is full.

So, for small input files, everything goes into a buffer. When you try to
read a line from the last file, there are no lines; the loop ends, the
buffer flushes, and all is well.

For larger input files, the buffer gets flushed earlier, so there are
actual lines to read from the last file. Those lines get read, then
written to the end of the file, where they are read again, and written
again, and read, and written...

As Joel suggested: ARGV.pop
 

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

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top