I find myself repeating a lot of:
mkdir longtitleproject
cd longtitleproject
Is there a way of doing it in one line without repeating the directory name? I'm on bash here.
I find myself repeating a lot of:
mkdir longtitleproject
cd longtitleproject
Is there a way of doing it in one line without repeating the directory name? I'm on bash here.
This is the one-liner that you need. No other config needed:
mkdir longtitleproject && cd $_
The $_
variable, in bash, is the last argument given to the previous command. In this case, the name of the directory you just created. As explained in man bash
:
_ At shell startup, set to the absolute pathname used to invoke
the shell or shell script being executed as passed in the envi‐
ronment or argument list. Subsequently, expands to the last
argument to the previous command, after expansion. Also set to
the full pathname used to invoke each command executed and
placed in the environment exported to that command. When check‐
ing mail, this parameter holds the name of the mail file cur‐
rently being checked."$_" is the last argument of the previous command.
Use cd $_
to retrieve the last argument of the previous command instead of cd !$
because cd !$
gives the last argument of previous command in the shell history:
cd ~/
mkdir folder && cd !$
you end up home (or ~/ )
cd ~/
mkdir newfolder && cd $_
you end up in newfolder under home !! ( or ~/newfolder )
mkdir foo && cd foo
, which isn't handy.
– josemigallas
Jun 13 '17 at 13:08
&& cd $_
since the keys are so far away from the home row, so while technically correct, it's not ergonomic. I appreciate the fact that it's not environment dependent and it's useful to know. Thanks!
– methodofaction
Feb 16 '19 at 22:06
mkdir newfolder && cd newfolder
is also strictly a one-liner.
– methodofaction
Aug 10 '20 at 15:02
&&
instead of ;
, as the &&
version breaks if the directory already exists, while the other works in every situation.
– Jonathon
May 28 '22 at 22:48
There's no built-in command, but you can easily write a function that calls mkdir
then cd
:
mkcd () {
mkdir "$1"
cd "$1"
}
Put this code in your ~/.bashrc
file (or ~/.kshrc
for ksh users, or ~/.zshrc
for zsh users). It defines a function called mkcd
. "$1"
will be replaced by the argument of the function when you run it.
This simple version has several defects:
-p
option to mkdir
. (This may or may not be desirable, as it increases the risk of a typo going undetected, e.g. mkcd mydierctory/newsub
will happily create mydierctory
and mydierctory/newsub
when you meant to create newsub
inside the existing mydirectory
.)-
but isn't just -
, then mkdir
and cd
will interpret it as an option. If it's just -
, then cd
will interpret it to mean $OLDPWD
. If it's +
followed by 0 or more digits, then cd
in zsh will interpret it as an index in the directory stack. You can fix the first problem, but not the other two, by passing --
before the argument. You can fix all of these problems by prepending ./
to the argument if it's a relative path.mkdir
doesn't follow CDPATH
, but cd
does, so if you've set CDPATH
to a value that doesn't begin with .
(an admittedly somewhat unusual configuration), then cd
may bring you to a different directory than the one that was just created. Prepending ./
to relative paths fixes this¹ (it causes CDPATH
to be ignored).mkdir
fails, it tries to execute cd
. Fix: use &&
to separate the two commands.Still fairly simple:
mkcd () {
case "$1" in /*) :;; *) set -- "./$1";; esac
mkdir -p "$1" && cd "$1"
}
This version still has the potential to make cd
go into a different directory from the one that mkdir
just created in one edge case: if the argument to mkcd
contains ..
and goes through a symbolic link. For example, if the current directory is /tmp/here
and mylink
is a symbolic link to /somewhere/else
, then mkdir mylink/../foo
creates /somewhere/foo
whereas cd mylink/../foo
changes into foo
(which is /tmp/here/foo
). It's not enough to look for symbolic links in the argument, because the shell also tracks symbolic links in its own current directory, so cd /tmp/mylink; mkdir ../foo; cd ../foo
does not change into the new directory (/somewhere/else/foo
) but into /tmp/foo
. A fix for this is to let the cd
builtin resolve all ..
path components first (it doesn't make sense to use foo/..
if foo
doesn't exist, so mkdir
never needs to see any ..
).
We come to this robust if slightly gory version:
mkcd () {
case "$1" in
*/..|*/../) cd -- "$1";; # that doesn't make any sense unless the directory already exists
/*/../*) (cd "${1%/../*}/.." && mkdir -p "./${1##*/../}") && cd -- "$1";;
/*) mkdir -p "$1" && cd "$1";;
*/../*) (cd "./${1%/../*}/.." && mkdir -p "./${1##*/../}") && cd "./$1";;
../*) (cd .. && mkdir -p "${1#.}") && cd "$1";;
*) mkdir -p "./$1" && cd "./$1";;
esac
}
(Exercise: why am I using a subshell for the first cd
call?)
If mkdir fails, I want to be sure not to change the current directory. Changing back with cd - or $OLDPWD isn't good enough if the shell doesn't have permission to change into its current directory. Also, calling cd updates OLDPWD, so we only want to do it once (or restore OLDPWD).
There are also less specialized ways to not have to retype the word from the previous line:
cd
, then Esc . (or Alt+.) to insert the last argument from the previous command.cd !$
executes cd
on the last argument of the previous command.mkdir
into cd
.¹ beware however that it doesn't work in ksh93 since the u+
version, fixed in 93u+m/1.0.0-alpha+d1483150 2021-01-05
ksh
, and also works in zsh
) sequence for "repeat last word of previous command". I use it quite often.
– geekosaur
Mar 12 '11 at 01:46
/a/b/..//
would actually work but not /a/b/../c
. Fixed. I've put the question to a broader audience.
– Gilles 'SO- stop being evil'
Jan 30 '13 at 22:26
mkcd() { mkdir -p "$1" && cd "$1"; }
doesn't seem to be a problem in (my instance of) zsh. mkdir -p /var/tmp/somewhere/else /tmp/here; cd /tmp/here; ln -s /var/tmp/somewhere/else mylink; mkdir -p mylink/../foo && cd mylink/../foo; pwd
(includes the setup and) displays /tmp/here/foo
which is what was created (and what I expected). bash
erroneously creates and changes to /var/tmp/somewhere/foo
.
– Adam Katz
Jan 15 '15 at 18:39
newdir=$(realpath -mL $1) && mkdir -p $newdir && cd $newdir
? This should ensure always using a resolved absolute path which shold overcome all edge cases, no?
– Dani_l
Jan 04 '21 at 23:45
..
, and both mkdir
and cd
worked as intended i.e. mkdir
made a directory at /somewhere/foo
and cd
changed the cwd to at /somewhere/foo
. Am i missing something ?
– xquilt
Feb 18 '22 at 06:45
mkdir mylink/../foo
creates /somewhere/else/foo
, but for me mkdir
creates /somewhere/foo
. Also the examples state that cd mylink/../foo
changes into foo
which is rather ambiguous without the indicating the path , but for me it changes into cd /somewhere/../foo
changes the directory to the foo that mkdir
created /somewhere/foo
.
– xquilt
Feb 18 '22 at 12:01
/somewhere/else/foo
was a mistake, I've fixed it, thanks. It's /somewhere/else/../foo
which is /somewhere/foo
. cd mylink/../foo
is equivalent to cd foo
in all the Bourne-style shells I remember seeing unless you disable symbolic directory tracking (e.g. with alias cd='cd -P'
)
– Gilles 'SO- stop being evil'
Feb 18 '22 at 16:32
cd
aliased with this flag . Also, I'm sorry for the befuddling typos that i made at my previous reply .
– xquilt
Feb 19 '22 at 01:32
If you use Oh My Zsh, there's a command called take that does exactly this. It would look something like this.
take myfolder
I actually found this one by accident. I just looked and it's listed on this cheatsheat from the Oh My Zsh GitHub wiki. It's quite a useful command, and apparently very easy to create yourself.
take
:) Perfect! btw - iTerm2 with Oh My Zsh. There are actually 3 perfect answers here. This one, the one by @jesús-carrera , and the selected answer. Depends on your setup and preference.
– Wade
Feb 14 '19 at 02:12
It would never have occurred to me to script up this behaviour because I enter the following on a near-hourly basis ...
$ mkdir someDirectory<ENTER>
$ cd !$
where bash kindly substitutes !$
with the last word of the last line; i.e. the long directory name that you entered.
In addition, filename completion is your friend in such situations. If your new directory was the only file in the folder a quick double TAB would give you the new directory without re-entering it.
Although it's cool that bash allows you to script up such common tasks as the other answers suggest I think it is better to learn the command line editing features that bash has to offer so that when you are working on another machine you are not missing the syntactic sugar that your custom scripts provide.
As per What customizations have you done on your shell profile to increase productivity?, this is how I do it:
# make a directory and cd to it
mcd()
{
test -d "$1" || mkdir "$1" && cd "$1"
}
it means it also works if the directory already exists.
mcd
command? Which package or project provides this command?
– Mikel
Apr 13 '11 at 22:05
Or you could just create a short variable on-the-fly and use it twice x = longproject ; mkdir $x ; cd $x
- which I admit is still longer than using a shellscript function :)
This is a simple thing to do in a bash script/function. I created a very readable and sufficiently documented tutorial including scripts that works on both Linux and MacOS (this will also be maintained in the future).
My goal for the tutorial complexity is: written for a targeted audience with the only prerequisites being the user has a pulse and can read English, so please provide feedback if you need assistance.
https://github.com/craigopie/shellscripts
mcdir() {
if [ $# -eq 0 ] || [ $1 = "-h" ] || [ $1 = "--help" ]
then
echo "Usage: [option...] {directory}"
echo " -p, --path Create all directories in path "
echo " -h, --help Shows this helpful information "
echo
return 0
fi
## create directory with a path
if [ $1 = "-p" ] || [ $1 = "--path" ]
then
mkdir -p "$2" &>/dev/null
if [ $? -gt 0 ]
then
echo "There was a problem creating your directory."
return 1
fi
cd "$2" &>/dev/null
if [ $? -gt 0 ]
then
echo "Unable to change into that directory."
return 1
fi
return 0
fi
## create directory in this location
mkdir "$1" &>/dev/null
if [ $? -gt 0 ]
then
echo "There was a problem creating your directory."
return 1
fi
cd "$1" &>/dev/null
if [ $? -gt 0 ]
then
echo "Unable to change into that directory."
return 1
fi
return 0
}
export -f mcdir
To install this you have two options:
.bashrc
file..bash_profile
file.Again, the README file is very detailed on how to do this.
Good luck!
If you are using Oh-my-zsh, take
command will do the trick. Take a look at the cheat sheet.
Here's a slight variant which is worthy of mention:
function mkdir() {
local dir=$1
command mkdir "$dir" && cd "$dir"
}
Add this to your ~/.bash_profile
and you can then use mkdir
as normal (once you've source
'd it), except now it will run the function above rather than the standard mkdir
command.
Note, this does not validate input as per the accepted answer by Gilles, but demonstrates how you can (effectively) override builtins.
From the docs (paraphrasing slightly):
command mkdir [args]
runsmkdir
withargs
ignoring any shell function namedmkdir
. Only shell builtin commands or commands found by searching the PATH are executed. If there is a shell function namedls
, runningcommand ls
within the function will execute the external commandls
instead of calling the function recursively
I believe builtin
achieves a similar result to command
.
command
as an alternative.
– Arj
Sep 07 '17 at 09:07
Create mkcd
command to your environment in one line
echo -e 'mkcd() {\n mkdir -p "$1" && cd $_\n}' >> ~/.${0//-/}rc && . ~/.${0//-/}rc
I know the user is in Bash, but I use both Bash and Fish. For Fish shell users, you can use this function (source), just put it into a file called ~/.config/fish/functions/mkcd.fish
and restart your terminal, then use mkcd FOLDERNAME
function mkcd -d "Create a directory and set CWD"
command mkdir $argv
if test $status = 0
switch $argv[(count $argv)]
case '-*'
case '*'
cd $argv[(count $argv)]
return
end
end
end
Just automated the above answers and made a one time executable script:
fun='
mkcd ()
{
mkdir -p -- "$1" && cd -P -- "$1"
}'
echo "$fun" >> ~/.bashrc
Just copy this in a new file mkcd.sh
and run it only once in terminal by bash mkcd.sh
.
Then execute source ~/.bashrc
to make it working in the current session.
After this, you can use mkcd some_dir
to create and enter directly in that directory.
~/.bashrc
file (with an answer that has already been given)? And how do you suggest creating this mkcd.sh
script? With an editor, perhaps? This looks like more work than just editing ~/.bashrc
. What advantage does this have over the accepted answer? … … … … … … … … … … … … … … … … … … … … … … … … … … … P.S. This will fail because of quoting issues, which tells me that you haven’t even tried it yourself.
– Scott - Слава Україні
Dec 11 '17 at 20:52
Good answers already posted.
You could also create an alias in .bashrc by adding
alias newdir mkdir %1;cd %1
at the bottom of .bashrc. After saving .bashrc and closing the terminal and opening a new terminal typing
newdir directoryname
Will execute
mkdir directoryname;cd directoryname
Note that if directoryname already exists this may display an error then cd to the directory. If you attempt to do newdir in a directory you don't have permission in you will get 2 errors if the directory doesn't already exist.
The advantage to this solution is that you don't have to remember to do ;cd $_ to create a new directory and change to it. Also, this "new" command will be persistent between reboots of the system, and opening new terminal instances.
mcd
from http://unix.stackexchange.com/questions/6628/what-customizations-have-you-done-on-your-shell-profile-to-increase-productivity – Mikel Mar 12 '11 at 01:32mkdir longtitleproject
thencd !^
– user262826 Nov 26 '17 at 18:38mkcd
as a built-in function. – Sam Sep 22 '21 at 08:18