Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I am writing a simple shell program. When I use /usr/bin/which with my shell in mac osx and ubuntu, it acts normally. When I use the exact same command on Red Hat Enterprise Linux Client release 6.3 (Santiago), I get this error: "which: no ANYCOMMANDHERE in ((null))".

Is there any intuition for this? I can't even find what the error means (Let me know if showing my source will help).

EDIT: My path is (from inside the shell):

$ echo $PATH
/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin

Thanks, Jon

share|improve this question
2  
What does echo $PATH say? It sounds like you have no PATH environment variable defined. –  cdhowie Oct 8 '12 at 21:19
    
It sounds like a $PATH problem. –  Blender Oct 8 '12 at 21:19
    
echo $PATH /usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin –  Jonathan Friedman Oct 8 '12 at 21:21
    
Why are you using which in a shell script anyhow? It's bad practice to do so; if you really to know where things are, use the shell builtin type, but if you just want to start them, just call your commands without qualifying and let the shell find them. There's no reason to call $FOO when you can just call foo. –  Charles Duffy Oct 8 '12 at 21:23
    
Charles Duffy. I'm writing a shell. Not a bash program. –  Jonathan Friedman Oct 8 '12 at 21:25
show 2 more comments

migrated from stackoverflow.com Oct 8 '12 at 22:29

This question came from our site for professional and enthusiast programmers.

4 Answers

The string (null) is substituted by some C libraries for arguments to printf's %s (string) conversion specifier, when the corresponding argument is a NULL pointer, e.g. for

 char *path = 0; /* This would normally be = getenv("PATH"). */
 printf ("which: no foobar in (%s)\n", path);

It appears that either your PATH environment variable is unset, or not exported. In these cases getenv("PATH") returns 0. As a last possibility, your which utility might have a mighty bug).

Does it work properly if you say export PATH?

share|improve this answer
    
Do you think it matters if I'm using /bin/tcsh (just realized that is the default on the server)? (Export isn't built in to tcsh I think (or my shell)) –  Jonathan Friedman Oct 8 '12 at 21:32
    
A csh variant? Ugh :-) Then you should say setenv PATH=...your path here... –  Jens Oct 8 '12 at 21:40
    
But wouldn't it not matter since which is getting called from my shell? And if it does, how can I make this portable? Also, I dropped into /bin/sh, and ran my shell from there, and it didn't work. –  Jonathan Friedman Oct 8 '12 at 21:41
    
It matters because you want to make sure your PATH is exported to the environment. The Bourne Shells do this with export, the csh lineage with setenv. We want to make sure PATH is set, so we can find if there's a problem in the which utility or somewhere else. –  Jens Oct 8 '12 at 21:43
    
$ echo $PATH /usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin. My bad.. I posted this in an edit. –  Jonathan Friedman Oct 8 '12 at 22:02
show 3 more comments

I can reproduce the same output from tcsh:

env -u PATH which ls
which: no ls in ((null))

In csh and tcsh, there's a distinction between environment variables (which are common to all processes) and shell variables (which are local to the current invocation of the shell). It uses the same syntax to refer to both, e.g., $PATH. If you have a shell variable and an environment variable of the same name, then $PATH refers to the shell variable.

[t]csh uses different syntax to set shell vs. environment variables:

set shell_var = foo
setenv env_var bar

(Bourne-based shells such as bash have a different syntax and a different terminology; an environment variable is a shell variable that's been "exported", or that's inherited from the calling process.)

Based on the symptoms you describe, you have a shell variable $PATH (which is useless), but no environment variable of the same name. That shouldn't normally happen. Check your .cshrc, .tcshrc, and/or .login files for statements that set $PATH.

You should be able to work around the immediate problem like this:

setenv PATH "$PATH"   # set the environment variable
unset PATH            # unset the shell variable, just to avoid confusion

(Don't do the unset PATH until you've confirmed that things are working correctly.)

Just to add to the frivolity, [t]csh has a special shell variable $path (note lowercase); its value is an array consisting of the :-separated components of the $PATH environment variable. Setting either will automatically update the other:

 setenv PATH /usr/bin:/bin # sets $path to ( /usr/bin /bin )
 set path = ( /usr/local/bin $path ) # sets $PATH to '/usr/local/bin:/usr/bin:/bin'

This can be convenient, but if you prefer you can just ignore $path and deal with $PATH. Just make sure that you're setting the environment variable $PATH (using setenv), not the useless shell variable of the same name.

share|improve this answer
    
Thanks for the info! I think it might have to do with default env var passing to children with fork. I'm not 100% though.. still testing. –  Jonathan Friedman Oct 9 '12 at 1:22
    
Children created by fork() inherit the $PATH environment variable of their parents. Every process should have a default $PATH. If $PATH is unset for a given process, something must have unset it explicitly. –  Keith Thompson Oct 9 '12 at 4:38
add comment

It sounds like your PATH environment variable is the problem. For instance, if you run which asdf normally you will get something like:

which: no asdf in (/usr/local/bin:/usr/bin:...)

So it appears your PATH environment variable is something like (NULL). The other possibility is that there's something wrong with the which binary on your RHEL box.

share|improve this answer
add comment

So it turns out the issue is specific to redhat and the forking mechanism. Child processes are not given the default env vars while in ubuntu and mac osx they are. This means that I had to explicitly set the envp to the parent's (in a call to execve).

Apologies for the misleading phrasing in my question (although it is hard to pinpoint these type of things).

Thanks for all the help! Jon

share|improve this answer
    
Er. This makes no sense. How were you calling fork/exec before? –  Random832 Oct 9 '12 at 5:16
    
I wasn't explicitly passing the environment variables to the child. There apparently is a difference between the different linux flavors for this behavior. –  Jonathan Friedman Oct 9 '12 at 19:26
    
My point was, what exactly did your call to exec look like? You can't just leave them out if you call execve/execle, and if that worked it only did so by accident - you have to call execv/execl to get it to implicitly pass the parent's environment. I'm asking this because there's not actually a difference, or any sane reason for there to be a difference, if you did it right. It's also possible that none of them were getting the parent's environment, and the implementation of /usr/bin/which (which is not a standard tool) was doing something different. –  Random832 Oct 9 '12 at 22:48
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.