# Kernel#system bug?

**URL:** <https://www.ruby-forum.com/t/kernel-system-bug/80036>\
**Category:** Ruby\
**Created:** [December 20, 2006, 10:46pm UTC](https://www.ruby-forum.com/t/kernel-system-bug/80036 "2006-12-20T22:46:25Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![charlton](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/c5a1d2/32.png) [@charlton](https://www.ruby-forum.com/u/charlton)\
**Post date:** [December 20, 2006, 10:46pm UTC](https://www.ruby-forum.com/t/kernel-system-bug/80036/1 "2006-12-20T22:46:25Z")

</div>

Running Ruby 1.8.4 on Linux

This problem seems to exist with the system() function but also has the  
same problem with IO#popen. Seems the working directory of a subshell  
can be affected by the command being executed? In the first call to  
popen, I’m just executing “env”. In the second, I’m calling “env;”  
(with a semicolon. I encountered this because some commands I was  
calling with system() were unable to find files that should have been  
in the directory that I chdir’d to.

Program and Output below.

Thanks,  
Charlton

Program:

Dir.mkdir(“bug”) if !FileTest.exists?(“bug”)  
File.open(“bug/bugfile”, “w”) { |file|  
file \<\< “Bug!”  
}  
Dir.chdir(“bug”)

puts “without semi-colon”  
IO.popen(“env”).readlines.each do |entry|  
puts entry if entry =~ /PWD/  
end

puts “with semi-colon”  
IO.popen(“env;”).readlines.each do |entry|  
puts entry if entry =~ /PWD/  
end

Output:

without semi-colon  
PWD=/user/blah/tests/ruby  
with semi-colon  
PWD=/user/blah/tests/ruby/bug

---

<div class="post-metadata">

**Author:** ![charlton](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/c5a1d2/32.png) [@charlton](https://www.ruby-forum.com/u/charlton)\
**Post date:** [December 20, 2006, 11:58pm UTC](https://www.ruby-forum.com/t/kernel-system-bug/80036/2 "2006-12-20T23:58:50Z")

</div>

On Dec 20, 2006, at 13:45, Charlton wrote:

> Running Ruby 1.8.4 on Linux
> 
> This problem seems to exist with the system() function but also has  
> the  
> same problem with IO#popen. Seems the working directory of a subshell  
> can be affected by the command being executed? In the first call to  
> popen, I’m just executing “env”. In the second, I’m calling “env;”  
> (with a semicolon. I encountered this because some commands I was  
> calling with system() were unable to find files that should have been  
> in the directory that I chdir’d to.

See the recent discussion on ruby-core.

–  
Eric H. - removed\_email\_address@domain.invalid - [http://blog.segment7.net](http://blog.segment7.net)

I LIT YOUR GEM ON FIRE!

---

<div class="post-metadata">

**Author:** ![charlton](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/c5a1d2/32.png) [@charlton](https://www.ruby-forum.com/u/charlton)\
**Post date:** [December 21, 2006, 1:57am UTC](https://www.ruby-forum.com/t/kernel-system-bug/80036/3 "2006-12-21T01:57:04Z")

</div>

Hi,

At Thu, 21 Dec 2006 06:45:06 +0900,  
Charlton wrote in [ruby-talk:230639]:

> ```
> puts entry if entry =~ /PWD/
> 
> ```
> 
> PWD=/user/blah/tests/ruby  
> with semi-colon  
> PWD=/user/blah/tests/ruby/bug

It is natural result.  
PWD is not set by OS automatically, but set by sh.

You should use getcwd() in C or Dir.pwd in ruby instead of  
relying on $PWD.

---

<div class="post-metadata">

**Author:** ![charlton](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/c5a1d2/32.png) [@charlton](https://www.ruby-forum.com/u/charlton)\
**Post date:** [December 21, 2006, 7:41am UTC](https://www.ruby-forum.com/t/kernel-system-bug/80036/4 "2006-12-21T07:41:36Z")

</div>

Hi Nobu,

Hm, I’m not sure I understand how this is natural. It’s true that the  
shell sets PWD but if I’m executing the same command from within a  
Kernel#system call, I would have expected the directory context to be  
consistent. If the directory viewed by the shell isn’t coherent with  
wherever I’ve taken ruby to (via Dir.chdir), then I would almost say  
it’s a busted implementation.

Cherers,  
Charlton

---

<div class="post-metadata">

**Author:** ![charlton](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/c5a1d2/32.png) [@charlton](https://www.ruby-forum.com/u/charlton)\
**Post date:** [December 21, 2006, 7:45am UTC](https://www.ruby-forum.com/t/kernel-system-bug/80036/5 "2006-12-21T07:45:36Z")

</div>

Thanks, Eric. I see the discussion over at ruby-core. Unfortunately, I  
don’t really understand the resolution (if there is one). I’ll keep my  
eyes on the mailing list.

Cheers,  
Charlton

---

<div class="post-metadata">

**Author:** ![charlton](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/c5a1d2/32.png) [@charlton](https://www.ruby-forum.com/u/charlton)\
**Post date:** [December 21, 2006, 4:48pm UTC](https://www.ruby-forum.com/t/kernel-system-bug/80036/6 "2006-12-21T16:48:38Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![charlton](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/c5a1d2/32.png) [@charlton](https://www.ruby-forum.com/u/charlton)\
**Post date:** [December 22, 2006, 2:56am UTC](https://www.ruby-forum.com/t/kernel-system-bug/80036/7 "2006-12-22T02:56:22Z")

</div>

Thanks, Ara,

That clarifies it beautifully. I wasn’t aware that Ruby actually looked  
behind the scenes for shell characters in order to determine whether or  
not to execute the SHELL. I understand the behaviour now. I guess the  
original program that caused me to run into this snag was Perforce  
(p4). It’s clearly using the PWD environment variable to do its work as  
is witnessed by:

tcsh\> ( setenv PWD dont\_exist ; p4 -v3 info | grep cwd )  
RpcSendBuffer cwd = dont\_exist

Thanks all for clarifying.

Cheers,  
Charlton

---

<div class="post-metadata">

**Author:** ![charlton](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/c5a1d2/32.png) [@charlton](https://www.ruby-forum.com/u/charlton)\
**Post date:** [December 21, 2006, 7:45pm UTC](https://www.ruby-forum.com/t/kernel-system-bug/80036/8 "2006-12-21T19:45:12Z")

</div>

“Charlton” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

> Hi Nobu,
> 
> Hm, I’m not sure I understand how this is natural. It’s true that the  
> shell sets PWD but if I’m executing the same command from within a  
> Kernel#system call, I would have expected the directory context to be  
> consistent. If the directory viewed by the shell isn’t coherent with  
> wherever I’ve taken ruby to (via Dir.chdir), then I would almost say  
> it’s a busted implementation.

Maybe this helps:

```
Dir.mkdir("bug") if !FileTest.exists?("bug")
Dir.chdir("bug")

puts "without semi-colon"
puts IO.popen("pwd").readlines
puts IO.popen("env").readlines.grep(/^PWD/)[0].split(/=/)[1]

puts "\nwith semi-colon"
puts IO.popen("pwd;").readlines
puts IO.popen("env;").readlines.grep(/^PWD/)[0].split(/=/)[1]

# >> without semi-colon
# >> /tmp/bug
# >> /tmp
# >>
# >> with semi-colon
# >> /tmp/bug
# >> /tmp/bug

```

The working directory _does_ change, but the PWD environment variable is  
set by the shell, not the operating system.

-Marshall
