Forum: Ruby Parsing unix filenames from STDIN

Posted by David Jacobs (Guest)
on 2012-08-27 14:01
(Received via mailing list)
How can I parse filenames read from STDIN via the standard Unix parsing 
rules (without duplicating said rules)? All of the following would be 
parsed as coherent file names:

file.txt
my\ file.txt
"my file.txt"

A nice addition would be that *.txt would use Bash expansion to find the 
appropriate files.

ARGF isn't working for me because it tries to actually read the files in 
(and some of the arguments in STDIN are commands, not filenames).

David
Posted by botp (Guest)
on 2012-08-27 14:01
(Received via mailing list)
On Sat, Aug 25, 2012 at 7:57 AM, David Jacobs <david@wit.io> wrote:
> ARGF isn't working for me because it tries to actually read the files in (and 
some of the arguments in STDIN are commands, not filenames).

try ARGV, eg,

$ echo p ARGV > test.rb

$ ruby test.rb file.txt my\ file.txt "my file.txt"
["file.txt", "my file.txt", "my file.txt"]

best regards -botp
Posted by Sean O'halpin (sean)
on 2012-08-27 14:04
(Received via mailing list)
On Sat, Aug 25, 2012 at 12:57 AM, David Jacobs <david@wit.io> wrote:
> How can I parse filenames read from STDIN via the standard Unix parsing rules 
(without duplicating said rules)? All of the following would be parsed as coherent 
file names:
>
> file.txt
> my\ file.txt
> "my file.txt"
>
> A nice addition would be that *.txt would use Bash expansion to find the 
appropriate files.

Use Shellwords to handle shell escaped strings and Dir[] to expand 
wildcards:

require 'shellwords'
while line = STDIN.gets
  filename = Shellwords.shellwords(line).join('')
  p filename
  # expand wildcards
  p Dir[filename]
end

Regards,
Sean
Posted by Robert Klemme (robert_k78)
on 2012-08-27 14:05
(Received via mailing list)
On Sat, Aug 25, 2012 at 11:51 AM, Sean O'Halpin <sean.ohalpin@gmail.com> 
wrote:
>
> require 'shellwords'
> while line = STDIN.gets
>   filename = Shellwords.shellwords(line).join('')
>   p filename
>   # expand wildcards
>   p Dir[filename]
> end

Two additional cents:

1. I'd rather use $stdin instead of STDIN, see here for reasoning:
http://stackoverflow.com/questions/4279604/what-is...

2. One can as well use the usual iteration for reading lines from files.

=>

require 'shellwords'

$stdin.each_line do |line|
  filename = Shellwords.shellwords(line).join('')
  p filename
  # expand wildcards
  p Dir[filename]
end

Advantage is also that the scope of "line" is limited to the block
reducing potential for errors.

Btw, Sean, are you sure David will join all the shellwords?  I am
asking since he said there were commands as well and he basically
wants to parse in the same way the shell does.  So:

irb(main):006:0> ['my\\ file.txt', '"my file.txt"', 'ls foo\\
bar.txt'].each {|s| printf "%p -> %p\n", s, Shellwords.shellwords(s)}
"my\\ file.txt" -> ["my file.txt"]
"\"my file.txt\"" -> ["my file.txt"]
"ls foo\\ bar.txt" -> ["ls", "foo bar.txt"]
=> ["my\\ file.txt", "\"my file.txt\"", "ls foo\\ bar.txt"]


Kind regards

robert
Posted by Sean O'halpin (sean)
on 2012-08-27 23:53
(Received via mailing list)
On Mon, Aug 27, 2012 at 10:51 AM, Robert Klemme
<shortcutter@googlemail.com> wrote:
>
> Two additional cents:
>
> 1. I'd rather use $stdin instead of STDIN, see here for reasoning:
> 
http://stackoverflow.com/questions/4279604/what-is...

Good point. I agree.

>   # expand wildcards
>   p Dir[filename]
> end
>
> Advantage is also that the scope of "line" is limited to the block
> reducing potential for errors.

Another good point.

> Btw, Sean, are you sure David will join all the shellwords?

No, I wrote my response after quickly reading his examples, not
by reading carefully to the end of his post.

>
Hat trick! I agree with all your points :)

>
> Kind regards
>
> robert
>
> --
> remember.guy do |as, often| as.you_can - without end

Indeed. All the best,
Sean
Posted by David Jacobs (Guest)
on 2012-09-01 06:23
(Received via mailing list)
Sorry for the delay. Thanks for the pointer to Shellwords and to 
iteration, guys!

David
Posted by David Jacobs (Guest)
on 2012-09-01 06:43
(Received via mailing list)
FYI I ended up using the following (turns out I didn't need bash 
expansion because I'll always get that from the previous tool in the 
pipeline):

if $stdin.tty?
  # … do something
else
  files = $stdin.each_line.reduce([]) do |list, line|
    list.concat(Shellwords.split(line))
  end


  # … do something with files
end
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.