My default shell (on Ubuntu) is bash. However, for a particular programme I need to change to the C-shell. For this I have a .cshrc file set up, however, if I change interactively to the C-shell (I'm using tcsh command for this) I notice that all the bash paths get imported.

Is there a way to stop importing these paths as some of them are incompatible with the programme I need to run. i.e. when I'm in the C-shell environment, I'd like to be able to define everything I need in the .cshrc file so I can control this. I don't want to change my login shell permanently however.

  • What do you mean "for a particular program I need to change to the C-shell"? An external program shouldn't care what shell starts it (for example, you can run the same mv command from bash or csh), and if you have a script written in C shell, you can run it with csh myscript from bash; the two shells don't interact. – chepner Oct 17 '17 at 16:38

Environment variables are always inherited from the parent process[†] so the .cshrc will need to manually set or remove any unwanted environment variables

setenv PATH /bin:/other/dirs/here:/and/more
unsetenv PS1

Note that these are exclusive operations (for which the English "or" is sadly lacking in boolean specificity). setenv PATH sets the PATH environment variable and unsetenv PS1 instead removes the unwanted PS1 environment. Doing unsetenv PATH and then setenv PATH ... would just waste CPU cycles. Instead, simply set PATH to what you want it to be. (Editing PATH is a much more complicated task, and will require splitting on : and then applying code for each directory element and so forth...why go to all that trouble? Set PATH to what it needs to be.)

Or, one can use env -i csh to totally blank out the environment in which case the .cshrc had better set everything that is necessary (various essential environment variables are set by login(1) or equivalent such as HOME and so forth):

$ env perl -E 'say $ENV{SHELL}'  
$ env -i perl -E 'say $ENV{SHELL}'


[†] Bourne shells complicate this by placing shell-only variables such as PS1 in the same namespace as the rest and then having a boolean (via export) that flags those that get passed along via extern char **environ to child processes; see the environ(7) and execve(2) man pages for more details on what is happening without the complication of the shell.

| improve this answer | |
  • It sounds like I shouldn't blank out the environment completely. However, how can I use unsetenv to remove something from the path imported from bashrc? unsetenv path=path/I/want/to/remove doesn't seem to work? – 218 Oct 18 '17 at 9:13
  • I have also tried adding the following lines to my .cshrc: unsetenv PATH set path=($path /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin ) If I test-run this in the c-shell it clears the path (echo $PATH returns PATH: Undefined variable). However, when I reset the path, all the paths I had defined in .bashrc (and which I'm trying to clear) are added back. – 218 Oct 18 '17 at 9:34
  • You would use unsetenv to completely unset something not wanted from the parent shell, such as PS1. Xor, you would use setenv PATH=/usr/local/blah:/de/blah:... to set PATH to what it needs to be in csh. Also do not mix the setenv PATH and set path=( forms, they are different, and use different syntax. – thrig Oct 18 '17 at 14:08

Is there a way to stop importing these paths

If you're editing .cshrc or .tcshrc anyway, you may prefer instead to allow the environment variables you don't want, or whose values you want to change, to be passed to tcsh. Then unset them or modify their values. That's what thrig's excellent answer explains how to do.

However, you can do exactly what you've asked for: run tcsh without the environment variables you don't want, or give them different values.

If you're running tcsh from a Bourne-style shell like bash then you can write VAR=val pairs before the command to set environment variables for that command. For example:

PATH=/sbin:/bin:/usr/sbin:/usr/bin tcsh

This is not the same as issuing the assignment as a separate command (by following it with a newline or a ; character). If you did that, it would not export the variable to the environment of subprocesses like tcsh, and the assignment would remain even after the next command were done running.

You can set multiple environment variables this way, too:

BAR=barval PATH=/sbin:/bin:/usr/sbin:/usr/bin tcsh

Observe that the environment variable remains unchanged for subsequent commands run in bash:

ek@Io:~$ echo "$LANG"
ek@Io:~$ LANG=C tcsh -c 'echo "$LANG"'
ek@Io:~$ echo "$LANG"

You can assign the empty string to an environment variable the same way:

FOO= tcsh

However, that's not the same thing as removing the variable entirely from the environment. To do that, you can use the env command with the -u option:

env -u FOO tcsh

You can also set environment variables with env:

env PATH=/sbin:/bin:/usr/sbin:/usr/bin tcsh

You don't usually need to do that from bash, though, since bash supports the VAR=val syntax.

You can set multiple environment variables with env and also unset variables, all in a single command. This is to say that you do not need to chain env commands. For example, you can use:

env -u FOO BAR=barval PATH=/sbin:/bin:/usr/sbin:/usr/bin tcsh

The actual command env runs begins with its first non-option argument that contains no = sign.

| improve this answer | |

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.