On Thu, 21 Dec 2006, Charlton wrote:
Hi Nobu,
Hm, I’m not sure I understand how this is natural. It’s true that the
shell sets PWD
and this here is the issue. in this command there is no shell involved:
puts “without semi-colon”
IO.popen(“env”).readlines.each do |entry|
puts entry if entry =~ /PWD/
end
which you can confirm thusly:
harp:~ > cat a.rb
IO.popen ‘env’
harp:~ > strace -f – ruby a.rb 2>&1|grep exec
execve("/home/ahoward/bin/ruby", [“ruby”, “a.rb”], [/* 52 vars /]) =
0
set_thread_area({entry_number:-1 -> 6, base_addr:0xb75e1460,
limit:1048575, seg_32bit:1, contents:0, read_exec_only:0,
limit_in_pages:1, seg_not_present:0, useable:1}) = 0
execve("/bin/env", [“env”], [/ 52 vars */]) = 0
set_thread_area({entry_number:-1 -> 6, base_addr:0xb75e2780,
limit:1048575, seg_32bit:1, contents:0, read_exec_only:0,
limit_in_pages:1, seg_not_present:0, useable:1}) = 0
yet a semi-colon terminated command does indeed invoke /bin/sh:
harp:~ > cat b.rb
IO.popen ‘env;’
harp:~ > strace -f – ruby b.rb 2>&1|grep exec
execve("/home/ahoward/bin/ruby", [“ruby”, “b.rb”], [/* 52 vars /]) =
0
set_thread_area({entry_number:-1 -> 6, base_addr:0xb75e0460,
limit:1048575, seg_32bit:1, contents:0, read_exec_only:0,
limit_in_pages:1, seg_not_present:0, useable:1}) = 0
execve("/bin/sh", [“sh”, “-c”, “env;”], [/ 52 vars /]) = 0
set_thread_area({entry_number:-1 -> 6, base_addr:0xb75e0080,
limit:1048575, seg_32bit:1, contents:0, read_exec_only:0,
limit_in_pages:1, seg_not_present:0, useable:1}) = 0
execve("/bin/env", [“env”], [/ 50 vars */]) = 0
set_thread_area({entry_number:-1 -> 6, base_addr:0xb75e4780,
limit:1048575, seg_32bit:1, contents:0, read_exec_only:0,
limit_in_pages:1, seg_not_present:0, useable:1}) = 0
which you see here
puts “with semi-colon”
IO.popen(“env;”).readlines.each do |entry|
puts entry if entry =~ /PWD/
end
this is because the command ‘env;’ is, in fact, not valid. in a c
program you
will not be able to popen it. ruby, however, is kind, when it sees the
special
chars
“*?{}[]<>()~&|\$;’`”\n"
in your system call it runs your command via sh. this is doccumented
somewhere, though i forget where attm…
so what’s happening is that, in one case, you exec ‘env’ which simply
inherits
the parents env, including current value of PWD. in the second case you
actually exec sh, which sets ENV[PWD], which in turn runs env as a child
process.
in summary, nobu is right - simply use Dir.pwd and do not rely on
auto-magical
behaviour of child processes which set, or may not set, the PWD env var.
similarly, if you want to avoid the special handling of cmd strings
given to
system/popen, make sure the commands given are valid (in the ‘c’ sense)
so you
bypass ruby filtering them via /bin/sh.
regards.
-a