export CDPATH=.:~/.marks/
function mark {
ln -sr "$(pwd)" ~/.marks/"$1"
}
mark @name # create a bookmark
cd @name # jump to bookmark
cd @<tab> # list bookmarks
cd @n<tab> # auto-complete
cd @name/<tab> # can access sub-directories within bookmarks
Works best when bookmarks are prefixed by "@" or other special symbol. Additional advantage is that you can use the same function `cd` to navigate both bookmarked and regular directories.[1]: http://karolis.koncevicius.lt/posts/fast_navigation_in_the_c...
alias cd="cd -P" Another neat short hand is !$ which is an alias for the last argument of the previous command. This can be handy if one creates a new directory and wants to change into it without typing the the directory again. So commands would be
mkdir -p make/new/directory
cd !$
You've no idea how many years I've been thinking "This is Linux fer gawd's sake. Surely there must be some easy way to make a new directory and 'cd' to it in a single command!" But was never able to find or guess the right incantation.mkcd() { mkdir -vp "$1" && cd "$1"; }
mkcd() { mkdir -p "$@" && cd "$_"; }
Can someone please detail the differences between $! and $_? (Apologies if I'm missing something obvious)
alias tcd='a=`date +%s`;mkdir "$a" && cd "$a"'Further, holding Alt followed by numeric argument followed by dot, gives you an argument at a specific position. For example, Alt + 1, Alt + . copies the first argument.
# create a new directory and enter it
function mkd() {
mkdir -p "$@" && cd "$_";
}
And use it like: mkd fooWhat does: "mkd foo bar" do? It creates both directories, and cd's into "bar".
Might be worth checking that only one argument has been passed, or use "$*" which instead would treat all arguments as one parameter, and "mkd foo bar" would create a "foo bar" directory instead (and cd to it)
YMMV.
¹ https://github.com/ohmyzsh/ohmyzsh/blob/master/lib/functions...
Wrote about it here: https://henrikwarne.com/2018/08/11/my-favorite-command-line-...
That's great set of tips BTW.
FWIW, zsh without oh-my-zsh can be configured to do too this with "bindkey ' ' magic-space".
enter ()
{
mkdir -p "$1";
cd "$1"
} cd -
Hint: Change into directory called '-' can be done by cd ./-
I also use the mkcd alias / function: mkcd() { mkdir -p "$@" && cd !$; }
This allows creating multiple dirs and cd into the first one. mkcd test1 test2 test3 git checkout -
checks out the previous branch you were on, similar to cd -So the very small 50 LOC kd was born:
kd # jumps to project top level (based on .git/Gemfile)
kd foobar "$PWD" # saves an entry named foobar pointing to $PWD
kd foo # jumps to foobar
cp qux $(kd foo) # expands to foobar's value
I should probably make it expand to absolute paths so that I could change "$PWD" to .https://gist.github.com/pcdv/3c52d82f59fe9042793033d5e249b14...
g . # add current dir to bookmarks
g # list bookmarks
g del # open bookmarks in vi (should use $EDITOR ...)
g <regex> # jump to first matching bookmark
Wonder how many monthdays I saved compared to colleagues still navigating manually :DFor exploring massive file trees, a terminal file manager that allows you to preview the contents of subdirectories without entering them is huge time saver. I use `lf`.
I love Z but I cannot believe there isn't something better yet?
One thing I'd love is something that helps navigating the current git project easier.
Every once and then I decide to use and love the fish shell, and I commit to using it exclusively for a few days. My first session always starts with 40 minutes trying to disable all stupid colors. I don't like my terminal to look like a kitsch Christmas tree! Then, I feel frustrated with "jumps" of the interface when editing multi-line command lines; inevitably leading me to quit fish and go back to bash. I'm obviously not smart enough to appreciate the defaults that these smart people have created.
It get critiqued a lot, but I'd suggest others try it out before dismissing it and see if it works for them.
alias ..='cd ..'
# etc ...
But not. shopt -s autocd
zsh also has this. This seems like the fastest way to navigate since you no longer need to type, or retype, cd. cdof () {
cd "$(dirname $1)"
}
as in 'Change into Directory Of"Changes into the directory of a file. This is useful when you're doing complicated commands with long path names, but realize it would be easier if you were to cd into that directory. Use in combination with <Alt+.>. Especially useful if the filename component is long:
$ pwd
=> ~/
$ ls -l path/to/whatever/deep/somewhere/2021-04-22-filewithverylongnamefoobarbaz.xyz
$ cdof <Alt+.>
$ pwd
=> path/to/whatever/deep/somewhere function cd() {
if [[ ${#} -eq 0 ]]; then
builtin cd
return
fi
if [[ -f ${1} ]]; then
builtin cd $(dirname ${1})
else
builtin cd ${1}
fi
}function gothere {
cd $(dirname -z `find -iname $1`)
}Note that many of these are not just for Bash. pushd/popd is near universal among shells and CDPATH is standard among SYSV shells.
The idea of a shortcut for cd .. and its repetitions is good, but I'd prefer alias p='cd ..', pp='cd ../..' and so on, since I balk at the idea of having to distinguish, e.g., ..... and ...., but I find pppp and ppp are easier to discriminate by eyeball.
The shells I use most often are bash and the Emacs eshell, and over the years I appreciate eshell more and more. It has a few footguns, but the availability of the various selection-narrowing libraries, dired and tramp are huge pluses. zsh can pretty much do anything bash can do and more, and it's default on Macos and Arch Linux.
But I still use some of the old techniques as they continue to save time/typing - particular "$!". And even though I've reduced my reliance on aliases, I'm so used to jumping between directories that "pd" (pushd) and "nd" (pushd +1) are some of the few I continue to find myself installing.
The other shell techniques (strictly speaking editing features) that I was surprised to find are generally less used these days are the shortcuts like CTRL-w to delete the word to the left of the cursor or CTRL-a, CTRL-e to navigate to the start and end of the current line.
Me too, my first contact with UNIX was with SunOS 4 in 1988, which had csh as its default shell. I don't think I switched to bash until I started administering a Linux box in 1999, although I did script in POSIX shells before then. Before I had a system I was in control of, my attitude to bash was that it was unportable, because of the major differences between its v1 and v2 syntax.
Edit: ESC followed by backspace seems to work.
export MARKPATH=$HOME/.marks function jump { cd -P $MARKPATH/$1 2>/dev/null || echo "No such mark: $1" } function ju { cd -P $MARKPATH/$1 2>/dev/null || echo "No such mark: $1" } function mark { mkdir -p $MARKPATH; ln -s $(pwd) $MARKPATH/$1 } function unmark { rm -i $MARKPATH/$1 } function marks { ls -l $MARKPATH | sed 's/ / /g' | cut -d' ' -f9- | sed 's/ -/\t-/g' && echo }
I think the original source is #http://jeroenjanssens.com/2013/08/16/quickly-navigate-your-f...
Another neat trick is to set you .inputrc to vi mode with
set editing-mode vi set keymap vi
and then put this in your .bashrc
bind -m vi-insert -x '"\C-h"':'"pushd . 1>/dev/null 2>/dev/null && cd ../ && echo -e ${LILA} $PWD && ls"' bind -m vi-insert -x '"\C-n"':'"popd 1>/dev/null 2>/dev/null && echo -e ${LILA} $PWD && ls"' bind -m vi-insert -x '"\C-b":"cd $HOME && echo -e ${LILA} $PWD && ls"'
This enables you to go a directory up using ctrl-h and go back using ctrl-n.
up <#> - cd .. # times
upto <dir> - find dir in the current path above you and cd to it
down <dir> - find dir in the current tree below you including inside any number of subdirectories and cd to it
https://github.com/robmccoll/dotfiles/blob/master/bashrc#L15...
# fuzzy search any command
f(){
ROOT_DIR="."
[ -n "$2" ] && ROOT_DIR="$2"
FZF_OUT=`fd . -H --color=always "$ROOT_DIR" --exclude "Software/"| fzf --query="$3"`
[ -n "$FZF_OUT" ] && "$1" "$FZF_OUT"
}
in my case Software/ is a directory with lots of files I don't need so I exclude it from my searches. I also like using ranger, it has very nice bookmarking and launcher features.Works for git too:
`git checkout -` (checkout previous branch)
`git merge -` (merge with previous branch; useful for pulling master before merging)
I've really taken a shine to using a real file manager with lots of nifty features without any bloat.
- I define "cdn" to be what others call "mkcd", as then if I have a command line "cd foo" and it tells me that foo doesn't exist, I can just add the 'n' to the previous entry. I also overload "cdn" so that when not given any argument, it goes into the newest subdirectory in the current directory.
- "u", "uu", "uuu", "uuuu", "uuuuu" for going "up" that many levels, and unlike the aliases in OP, I define them as functions and if those are given an argument, they descends into the path from there: "u foo" is equivalent to "cd ../foo", "uu foo" to "cd ../../foo".
- I also have a function called "mvcd foo bar" that moves foo to bar and then goes into bar. "mvcdnewdir foo bar" that does the same but will create bar. (I'm pondering unifying them to a version that always calls mkdir -p)
- an alias "c" for cd [2]. The single letter messes with the history search though (ctl-r c space or ctl-r cd space ?), so it's not necessarily a good idea. `shopt -s autocd` that I just learned about here may be better.
- some functions for special locations, "cs" for ~/scratch, "cb" for ~/bookmarks, etc.
[1] see .bashrc at https://github.com/pflanze/chj-home [2] but I never use bash's "alias" since aside of being shorter it is always worse than a function (no way to extend it later to take parameters, and messes up live redefinitions)
n!!
(!! repeats the previous command).
https://github.com/danwills/shell-scripts/blob/bb989985d270c...
This makes all directories with names provided by args, including spaces and multiple levels (slashes) at once. It then enters the resulting directory as well (when aliased including 'cd' as advised in the comment).
# create a directory in the current directory and cd to it
function mkcd() { mkdir -p "$@" && eval cd "\"\$$#\""; } mkcd(){ mkdir --parents -- "$@" && cd -- "$@"; }Another thing that I've found surprisingly invaluable is an alias (i went for 'ccd') that figures out (via python, so a bit slower on the 1st run) what part of the argument is a valid directory and then cd's you there. It's very handy indeed when working with file paths all the time (a film-vfx-on-Linux use-case) otherwise you end up using backspace to delete the file part constantly! In fact, about that: hitting Esc-Backspace in sequence, should delete back to the next word separator instead of one char at a time.
function up() { for i in $(seq 1 $1); do cd ..; done }
# usage:
up # goes up 1 directory
up 2 # goes up 2 directories
up 42 # goes up 42 directories
function ..() { for i in $(seq 1 $1); do cd ..; done }
.. # goes up 1 dir
.. 2 # goes up 2 dirs
.. 42 # goes up 42 dirsI like the autocomplete, the fact that when cd-ing a known path you can just type the first leter of each directory with slashes, showing the git branch in working dir.
Its the little things.
If all the components of 'oh my zsh' were compiled into the shell and shared data structures, I bet it would be as fast as bash and only limited by IO
Bash is so amazingly clunky in comparison.
mkdir -p path/to/{one,two,three}/done
To create:* path/to/one/done
* path/to/two/done
* path/to/three/done
The methods listed in the article are almost certainly better if you know exactly which directory you need to go to (like a specific project repo, your bin etc) however often you don’t!
Another interesting tool is Z: https://github.com/rupa/z
https://gumroad.com/l/findspot
I experiment with many forms of automation and stick with few of them. Interface complexity has a cost; there's a reason keyboards don't have more keys. For me, Findspot is indispensable.
Up 3 will put me 3 directories behind the current one.
https://gist.github.com/iwalton3/3f9bfce510f959782404be25cab...
> alias u="cd .."
And on Dvorak, "u" is under the left index finger. Can't get faster than that ;)
https://gist.github.com/euske/4f06a6e060131949085c493bd28a0c...
edit: url
Really cool trick to navigate directories fast I’m definitely going to add this to my .zshrc
Honestly commandline has made so many things easier for me that I don’t even use regular apps besides my browser for browsing web anyhow using commandline has really made me productive
And I always look for automating or making the workflow better
Anyways great post thanks for sharing:)
# Expand ... to ../..
function vbe-expand-dot-to-parent-directory-path() {
case $LBUFFER in
(./..|* ./..) LBUFFER+='.' ;; # In Go: "go list ./..."
(..|*[ /=]..) LBUFFER+='/..' ;;
(*) LBUFFER+='.' ;;
esac
}
zle -N vbe-expand-dot-to-parent-directory-path
bindkey "." vbe-expand-dot-to-parent-directory-path
bindkey -M isearch "." self-inserthttps://github.com/huyng/bashmarks
cd /path/to/project1
s p1 # sets bookmark
cd /elsewhere
g p1
It also autocompletes bookmarks.There're only few directories I need to change to daily. So when I have to visit them, I need to type only `z first_two_characters_of_the_directory_name`
My favorite one is c to change to my ~/code directory with tab completion from anywhere. So I can type c pr<tab><enter> to cd in to ~/code/project from anywhere. (Full disclosure This is zsh and I don't have a bash equivalent for that)
Another thing I can't live without and some people hate is ls -la anytime I cd in to a directory. In a gui, I get that visual feedback immediately and it's usually the first thing I type when I land anyway so I just have a function for it https://github.com/gpspake/dotfiles/blob/master/zsh/gpspake/...
# When called as `argu string`, prints the closest ancestor directory which
# contains "string". If none is found, or "string" is empty, the current
# working directory is printed. This function is useful if you need to specify
# a file as an argument, but the relative path to it involves moving several
# directories up from the current directory. For example, instead of doing:
# $ pwd
# /this/is/a/very/long/directory/path/for/demonstration/purposes/
# $ ls ../../../../another/directory/something.log
# You could do:
# $ ls `argu dir`/another/directory/something.log
argu() {
if [[ "$1" == "" ]]; then
echo "`pwd`/"
return
fi
echo "`pwd | sed "s/^\(.*"$1"[^/]*\)\/.*$/\1/g"`/"
}
# When called as `cdu string`, changes directories into the closest ancestor
# directory of the current directory which contains "string". If none is found,
# or "string" is empty, no changes are made to the current directory.
cdu() {
cd `argu $1`
}
I also put the following in ~/.zsh/completion/_cdu so I can get tab-completion of the portions of the path: #compdef cdu
_cdu_parents=$(pwd | tr '/' ' ')
_arguments "1:parents:($_cdu_parents)"
Or bash (in ~/.bash/completion/cdu): # bash completion for cdu
_cdu()
{
local cur prev split=false
COMPREPLY=()
_get_comp_words_by_ref -n : cur prev
_dirs=$( pwd | tr '/' ' ' )
COMPREPLY=( $( compgen -W "$_dirs" -- "$cur" ) )
}
complete -F _cdu cdu
# Local variables:
# mode: shell-script
# sh-basic-offset: 4
# sh-indent-comment: t
# indent-tabs-mode: nil
# End:
# ex: ts=4 sw=4 et filetype=shLearn keyboard shortcuts to edit the current command line and you'll save years of your life.
ESC-. (dot) will get the last argument of the last command. This one alone will save you months.
CTRL-R will search backwards. This other will save more months.
That was over 10 years ago and I still use the shell with this in mind.
I’m not saying I never change directory, but once I do, I tend to stay there.
I had to scroll a fair way down to find a comment validating this opinion.
Perhaps we’re wrong when saying to change directory efficiently, you don’t.
And ~mylogin is another alias for ones home directory.
And more generally, ~otherdev is an alias for otherdev's home directory.
$ cd ~myproject
$ pwd
~/projects/myproject
shopt -s cdable_vars
p=/some/path/you/cd/to/a/bunch
cd p alias gd='cd "$(git rev-parse --show-toplevel)"' bind '"\e[A":"cd ..\n"'
But would you really want that rather showing previous command?