2

I have a number of BASH functions, which I have had in my /etc/bash.bashrc for a long time. They work there, in ~/.bashrc, and in OSX's ~/.bash_profile when written like this:

mcdir(){
    mkdir "$1";
    eval cd "$1";
}

This is just a short one, which I use daily, as an example. It simply makes a given directory and changes to it, the way mkdir "$1" && cd "$1" would do... I'm just lazy.

The point is that it works... I know it works, because I've been using it for years.

Now, I have recently removed it from my bashrc and put it into /usr/local/bin as mcdir (as well as chmod +x /usr/local/bin/mcdir), so that there really aren't any changes. Here, it looks something like this:

#!/bin/bash

mkdir "$1";
eval cd "$1";

This, for all intents and purposes, should work exactly like the above function. The problem is that it only works halfway. It will make the new directory, but NEVER change into it.

Does anybody know what I'm doing wrong here, and/or how to solve it?


Another example I have is a cdd function... in bashrc it looks like this:

cdd(){
    cd "$1";
    echo -e "\033[101m" $(pwd) "\033[49m";
    ls -l;
}

And that works perfectly! But, when I put it into its own script in /usr/local/bin and make it executable, like this:

cd "$1";
echo -e "\033[101m" $(pwd) "\033[49m";
ls -l;

It doesn't actually change into the directory. It will give me the pwd and the ls -l, but I won't change directory at all.

  • 3
    The script does create the dir, it does change directory to go in it, and then that script (launched in a subshell) exits, and you are back in your current shell, in its (former) current directory. – Olivier Dulac Nov 16 '17 at 16:28
  • @OlivierDulac Thanks... that clears it up, pretty well. So it's technically working, just not in the active shell I want it to. Is there any way to force it to work in the current, active shell... or to manipulate the current, active shell? – antiDill Nov 16 '17 at 16:32
  • @antiDill You can source a script to have it run it the current shell, e.g. source script.sh. I mention that in my solution. A common technique is to source other scripts from your ~/.bashrc. – igal Nov 16 '17 at 16:33
  • @antiDill I've updated my solution to include a recommendation for organizing your ~/.bashrc into separate files. – igal Nov 16 '17 at 16:36
  • @OlivierDulac @igal Thank you both... I have done some tinkering around, and you're both correct. It adds a couple of lines to my bashrc, but a net-loss of several lines. Not exactly what I was hoping for, but better than nothing! – antiDill Nov 16 '17 at 17:04
3

Scripts run in subshells. They can't affect the environment of your active shell session in the way that functions can. See, for example, the Advanced Bash-Scripting Guide, Chapter 21: Subshells:

A subshell is a separate instance of the command processor -- the shell that gives you the prompt at the console or in an xterm window. Just as your commands are interpreted at the command-line prompt, similarly does a script batch-process a list of commands. Each shell script running is, in effect, a subprocess (child process) of the parent shell.

Or the Bash Reference Manual, Section 3.8: Shell Scripts:

A shell script may be made executable by using the chmod command to turn on the execute bit. When Bash finds such a file while searching the $PATH for a command, it spawns a subshell to execute it. In other words, executing

filename arguments

is equivalent to executing

bash filename arguments

if filename is an executable shell script. This subshell reinitializes itself, so that the effect is as if a new shell had been invoked to interpret the script, with the exception that the locations of commands remembered by the parent (see the description of hash in Bourne Shell Builtins) are retained by the child.

If you want to use a script instead of a function you can source it instead of executing it, but honestly I think it's probably better to just stick to using functions (or aliases) for the kind of thing you're doing.

That said, if you want to reorganize the code in your ~/.bashrc then you can break it up into separate files and then source those files from ~/.bashrc, e.g. you can put them in a local subdirectory such as ~/.bashrc.d.

  • You say "can't" as if it's not possible, whatsoever. Is this true, or is there a workaround? – antiDill Nov 16 '17 at 16:10
  • @antiDill Well, anything is possible in principle. You might be able to write a script that runs some code that goes into RAM and modifies your active shell session (or something like that - way out of my depth there) but that wouldn't be a supported use-case. Give me a second and I'll add a couple of references. – igal Nov 16 '17 at 16:12
  • Thank you. I was just trying to "tidy" up my bashrc because it's LOADED with little aliases and functions, like this... I was able to put my aliases in /etc/profile.d/00-aliases.sh, and that saved some room, but I was hoping to do better... I guess I'll have to leave some elements in there. – antiDill Nov 16 '17 at 16:17
  • @antiDill : things involving 'cd' will have to stay in your bashrc. – Olivier Dulac Nov 16 '17 at 16:29
  • @OlivierDulac, or be sourced from the .bashrc. – RobertL Nov 16 '17 at 18:03

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.