241

is there any way (what is the easiest way in bash) to combine the following:

mkdir foo
cd foo

The manpage for mkdir does not describe anything like that, maybe there is a fancy version of mkdir? I know that cd has to be shell builtin, so the same would be true for the fancy mkdir...

Aliasing?

Jasper
  • 3,538
  • 4
  • 16
  • 22

4 Answers4

377

I think creating a function is the most appropriate way to do this, but just for listing all alternative ways, you could write:

mkdir foo && cd "$_"

$_is a special parameter that holds the last argument of the previous command. The quote around $_ make sure it works even if the folder name contains spaces.

Why use double quotes?

In some shells, such as zsh, the double quotes surrounding the $_ are not necessary even when the directory name contains spaces. They are required for this command to work in bash, however.

For example, running this command in bash 3.2.57 on macOS 10.13.6:

mkdir "my directory" && cd $_

results in this output:

bash: cd: my: No such file or directory

However, if we surround $_ with double quotes, the command returns successfully.

bash-3.2$ mkdir "my directory" && cd "$_"
bash-3.2$ echo $?
0
bash-3.2$
Zajn
  • 3,871
  • 2
  • 10
  • 6
  • 4
    Same line version of `$!`, in this case, is `!#:1`. i.e. `"$_"` can be replaced with `!#:1`. – antak Dec 07 '16 at 05:33
  • Strange, but this answer doesn't work for me. It works when I start `bash --norc`, but when config is active then `echo $_` echoes `$_`, while `echo ${_}` works. I couldn't find the reason. Probably `${_}` is more safe variation and should be used in the answer? – MarSoft Feb 02 '17 at 22:18
  • Also, without `--norc`, this command `echo abc; echo def; echo $_` echoes `abc def $_` (each on new line). When using `--norc`, the same command yields `abc def def` (each on new line). – MarSoft Feb 02 '17 at 22:23
  • @MarSoft Weird! I wonder if it's a difference in the version of `bash`? It works for me under `bash 4.3.46` whether if I supply `--norc` or not. I would be curious to see what your `bashrc` looks like if it works when starting the shell without config, even though I don't think you can modify special parameters like `_`. – Zajn Feb 02 '17 at 23:18
  • @Zajn, I found that the culprit is a [`git-prompt`](http://volnitsky.com/project/git-prompt/) script. Yet to determine how does it achieve such behaviour :) Probably any `PROMPT_COMMAND` will influence the `$_`? – MarSoft Feb 06 '17 at 17:58
  • 2
    @nyxee `$_`'s value will be `foo` in this example. If I had instead typed `mkdir workspace`, the value of `$_` would have been `workspace`, and `cd "$_"` would change our current directory to the newly created `workspace`. Does that make sense? – Zajn Feb 23 '17 at 15:56
  • Does not work inside of shell & works perfectly at command prompt. – user2067125 Jul 31 '17 at 12:25
  • 1
    why did you add the double quotation ? I just tried and It works without it. Also, it makes it look really ugly and might discourage some people – Suhaib Aug 09 '17 at 05:38
  • @Suhaib Without the double quotes, this command will not work correctly using `bash`. I've tried it in `zsh` and confirmed that it works without the double quotes, but since the question was tagged with `bash`, I answered accordingly. – Zajn Aug 10 '17 at 03:03
  • @Suhaib As explained in the answer, the double quotes ensure that the command works if the directory name contains spaces. Try running `mkdir "test folder" && cd $_` in `bash` and see the result. I should have specified in my last comment that this pertains to directories with spaces in their names. – Zajn Aug 10 '17 at 03:09
  • 1
    @SHiON Adding double-quotes is necessary in `bash` when creating a directory that contains spaces. Since the question is tagged for `bash`, I answered accordingly. – Zajn Oct 02 '18 at 18:52
  • 1
    I find it humorous that the best answer here is one that ends with an error: `bash: cd: my: No such file or directory`. I mean, it shows that the `cd` is being invoked and `my` is the argument but `pwd && mkdir thisdir && cd $_ && pwd` demonstrates the point without an error. All the same, TIL about the `$_` command. Thanks! – harperville Jan 15 '19 at 20:01
  • 2
    @harperville The reason for the error at the end of the answer is to demonstrate the need for quotes surrounding `$_` in certain shells, namely `bash`. Perhaps I should re-word that section to more clearly state that without the `"$_"`, that is the error you will see. – Zajn Jan 15 '19 at 20:52
188

Function?

mkcdir ()
{
    mkdir -p -- "$1" &&
       cd -P -- "$1"
}

Put the above code in the ~/.bashrc, ~/.zshrc or another file sourced by your shell. Then source it by running e.g. source ~/.bashrc to apply changes.

After that simply run mkcdir foo or mkcdir "nested/path/in quotes".

Notes:

  • "$1" is the first argument of the mkcdir command. Quotes around it protects the argument if it has spaces or other special characters.
  • -- makes sure the passed name for the new directory is not interpreted as an option to mkdir or cd, giving the opportunity to create a directory that starts with - or --.
  • -p used on mkdir makes it create extra directories if they do not exist yet, and -P used makes cd resolve symbolic links.
  • Instead of source-ing the rc, you may also restart the terminal emulator/shell.
Ouki
  • 5,842
  • 4
  • 23
  • 31
  • 13
    quotes around `"$1"` will protect the argument if it has spaces. – glenn jackman Apr 18 '14 at 13:33
  • 12
    and put this in .bashrc? – Jasper Apr 18 '14 at 14:05
  • exactly ;) ... no big deal – Ouki Apr 18 '14 at 14:25
  • @glenn jackman: thanks for the `"$1"` – Ouki Apr 18 '14 at 14:26
  • 7
    What's the purpose of `--`? – Zaz Nov 12 '16 at 21:25
  • 20
    @Zaz `-- ` is used to make sure that the following parameters are not parsed as a options to modify the behaviour of the command. In this case it makes sure the passed name for the new directory is not interpreted as an option to mkdir or cd, giving the option to create a directory that starts with - or -- . – immeëmosol Jan 04 '17 at 11:12
  • 22
    In case someone's wondering, the `-P` used makes cd resolve symbol links. The `-p` used on mkdir makes it create extra directories if they do not exists yet. – immeëmosol Jan 04 '17 at 11:14
  • I normally use $ mkdir gulp && cd gulp in my arch linux – Tofeeq Jan 23 '18 at 11:59
  • 1
    In case someone is wondering: You need to put the function in .bashrc and then add a line `export . Then `source ~/.bashrc` or restart terminal, and the function will be available as a command. I really think the comments should be integrated into the answer, but I don't want to intrude to someone else's answer. – Asotos Mar 24 '18 at 10:26
  • I am calling it `mc`! – nroose Dec 16 '18 at 05:06
  • Do we need an `|| exit` following the cd? e.g. `mkdir -p -- "$1" && cd -P -- "$1" || exit` – Mark Han Jan 06 '20 at 15:29
  • "exit" would mean "logout" : I am sure you do not want that ^^ – Ouki Jan 06 '20 at 15:41
  • when using oh-my-zsh there is a function `take` defined, so you can use something like `take somenewdir` . The function looks like this: `take () { mkdir -p $@ && cd ${@:$#} }` – qwertz Jun 09 '21 at 10:06
26

Bash (using word designators):

/tmp/bug$ mkdir "some dir"
/tmp/bug$ cd !$
cd "some dir"
/tmp/bug/some dir$ 

!$ expands to the last argument of the previous line in the history. If you have parameters in between, then you can use !:1 for the first argument, !:2 forthe second argument, etc.

From bash(1):

Event Designators

An event designator is a reference to a command line entry in the history list. Unless the reference is absolute, events are relative to the current position in the history list.

! Start a history substitution, except when followed by a blank, newline, carriage return, = or ( (when the extglob shell option is enabled using the shopt builtin).

[..]

Word Designators

Word designators are used to select desired words from the event. A : separates the event specification from the word designator. [..]

[..]
n The n-th word.
^ The first argument. That is, word 1.
$ The last word. This is usually the last argument, but will expand to the zeroth word if there is only one word in the line.

Lekensteyn
  • 20,173
  • 18
  • 71
  • 111
13

These other lads are just making life complicated, here it is:

eval {mkdir,cd}\ FOLDER\;
Sean D
  • 265
  • 2
  • 8
  • 3
    I really wanted to make a directory called `'FOLDER && rm ../something'`. But `eval` won't let me :*( Tragically, may have to choose complicated in the battle of complicated vs [evil](http://mywiki.wooledge.org/BashFAQ/048). –  Apr 19 '14 at 02:14
  • @BroSlow, well then you'll have to find another OS, since having a slash in a filename has never been allowed! as for the other characters they work just fine if escaped. – Sean D Apr 19 '14 at 10:20
  • 1
    @SeanD You're missing my point. Using `eval` with user input is generally a bad idea and `eval` will process `FOLDER && rm ../something` in place of `FOLDER` without complaint. Or for another variant, how about `"FOLDER && rm -r $HOME"` –  Apr 19 '14 at 17:28
  • 3
    @BroSlow This isn't using `eval` with user input, so it's fine. Don't cargo cult. – Miles Rout Jan 30 '16 at 06:56
  • 2
    @MilesRout If you only ever use it for a directory called `FOLDER`, sure, this is fine. That's not the point, if you use it with variable input (which you almost certainly are going to), the results for weird directory names can at best cause unexpected results, at worst pose a security risk. –  Feb 01 '16 at 01:36