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

Thanks, Jon

  • 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

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?

|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

Actually, what all other people here already answered - PATH not being set, is true in one way, but false in another way.

I had the same problem (using bash). It seems, a bash "feature" turns into a miss-feature: Bash creates a shell variable (not environment variable!) PATH which it then uses for lookups.

So, the situation is: There exists a shell variable called PATH. But it's not an environment variable. This means, it's not exported to newly created child processes. One thing, we should learn from this, is that using echo $PATH is no way to figure out whether the environment variable PATH is set. Same prolem with set | grep "^PATH=" However, one way to do so is by using the external command env: env | grep "^PATH="

Example shell session:

$ env -i bash
# A new shell is started with empty environment.
# What follows happens in this new shell:
$ echo $PATH
$ set | grep "^PATH="
$ env | grep "^PATH="
$ which ls
which: no ls in ((null))
$ export PATH
$ env | grep "^PATH="
$ which ls

Depending on what you're trying to achieve, you can ask the shell to act like a login shell, for bash it's -l. With that, /etc/profile and other files are sources which set up PATH properly by default:

$ env -i bash -l
$ which ls

The alternative, is to export PATH, see above.

|improve this answer|||||
  • Ran into this issue installing txt2man, and this resolved it. Much appreciated! – DMor Dec 30 '17 at 7:32

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.

|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

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.

|improve this answer|||||

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

|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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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