32

I'm using a tiling window manager and I switched from gnome-terminal with multiple tabs to multiple urxvt instances managed by the window manager. One of the features I miss is the ability to open a new terminal that defaults to the working directory of the last one.

In short: I need a way to open a new urxvt (bash) that defaults to $PWD of the last used one.

The only solution that comes to my mind is to save the current path on every cd with something like this:

echo $PWD > ~/.last_dir

and restore the path on the new terminal in this way:

cd `cat ~/.last_dir`

I can source the second command in .bashrc but I don't know how to execute the first one on every directory change :)

Any simpler solution that does not involve screen or tmux usage is welcome.

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
Luca
  • 593
  • 1
  • 5
  • 9

8 Answers8

17

I'm currently using this version of #1 solution

# save path on cd
function cd {
    builtin cd $@
    pwd > ~/.last_dir
}

# restore last saved path
if [ -f ~/.last_dir ]
    then cd `cat ~/.last_dir`
fi

inside my .zshrc

Luca
  • 593
  • 1
  • 5
  • 9
  • i'm using #1 solution too and add `trap "[ -f ~/.last_dir ] && rm ~/.last_dir" EXIT` i want start always in my home except when i open a new tab – rkmax Jul 12 '13 at 21:18
  • 1
    This doesn't work if using the `auto_cd` feature of zsh. It turns out we can use a hook that zsh provides: https://gist.github.com/jonleighton/1f0b96b49247a07dbaa30fbbe70b34f7 – jonleighton Aug 31 '19 at 23:49
13

This is actually pretty trivial; if you run urxvt from within your existing urxvt window, the new window will be in the same directory. I have dup aliased to urxvt & for this reason. If you want it bound to a hotkey, you can use bash's bind command. For example, to bind it to F1:

$ bind '"\e[11~": "urxvt &\n"'
Michael Mrozek
  • 91,316
  • 38
  • 238
  • 232
  • Thanks for the tip. I knew that terminal child processes maintained the state but I didn't know that you can bind a key to a command in bash. I'd like to do this from WM to avoid focusing the terminal. – Luca Feb 23 '12 at 19:12
  • I like that. No disk writes and the only execution takes place when you're about to open the new terminal. – rozcietrzewiacz Feb 23 '12 at 19:14
  • The only thing I'd change is to use `( urxvt & ) &>/dev/null` instead of just backgrounding. – rozcietrzewiacz Feb 23 '12 at 19:17
  • This solution is great and more flexible but I don't like to use 2 bindings, one to launch the terminal and one to fork a new one. – Luca Feb 23 '12 at 19:46
10

I see three solutions using .last_dir. You can place the echo $PWD > ~/.last_dir either:

  1. In a special function that would be a wrapper for cd:

    function cd_
    {
      [[ -d "$@" ]] || return 1
      echo "$@" > ~/.last_dir
      cd "$@"
    }
    

    Place this in your ~/.bashrc and then use cd_ instead of cd every time you want your new working directory to be stored.

  2. In your $PROMPT_COMMAND (not recommended):

    PROMPT_COMMAND="$PROMPT_COMMAND; pwd > ~/.last_dir"
    

    You can test this directly from the terminal or place it in ~/.bashrc. This solution, however, triggers a disk write each time the prompt appears, which might cause trouble - but on the other hand, .last_dir would contain the current directory no matter how you got there.

  3. In a custom perl extension script for rxvt. I've never created one myself, but you can find quite a few examples on the web.

Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
rozcietrzewiacz
  • 38,754
  • 9
  • 94
  • 102
  • PROMPT_COMMAND that's what I was looking for. I will try this solution hoping it doesn't affect performances. – Luca Feb 23 '12 at 19:25
  • Well, it is a rather crude way, frankly. Personally, I like Michael's solution best :) – rozcietrzewiacz Feb 23 '12 at 19:33
  • 1
    I like the perl extension way, if it needs to work outside of the terminal; it seems cleaner than hacking something into `PROMPT_COMMAND`, one of the most abused environment variables of all time – Michael Mrozek Feb 23 '12 at 19:37
  • It seems that $PWD is evaluated only the first time – Luca Feb 23 '12 at 21:25
  • @neon Aaah... Sorry. The problem is with with how the PROMPT_COMMAND is quoted. (Or rather, how `$PWD` was *not* quoted.) Let me fix this... There. That ought to do it. – rozcietrzewiacz Feb 23 '12 at 21:33
  • Thank you! There is a side effect of this solution, it remains after reboot/logout :) In my case is not a security issue but a nice feature. – Luca Feb 23 '12 at 22:19
  • 1
    https://bugs.launchpad.net/ubuntu/+source/gnome-terminal/+bug/1132700 For gnome-terminal just do: `. /etc/profile.d/vte.sh` – Ajax Apr 05 '15 at 23:20
7

Just add . /etc/profile.d/vte.sh in your ~/.bashrc to get the same feature

Anthon
  • 78,313
  • 42
  • 165
  • 222
david villa
  • 171
  • 1
  • 2
  • This work, however, why bother -1 this? – Abdillah Feb 17 '15 at 06:51
  • 3
    This works, and it looks like it's actually the preferred solution on launchpad / of gnome-terminal devs: https://bugs.launchpad.net/ubuntu/+source/gnome-terminal/+bug/1132700 – Ajax Apr 05 '15 at 23:19
  • And you have to put it before and hypothetical `PS1` modification. Here is a more "official" justification : https://wiki.gnome.org/Apps/Terminal/FAQ – Welgriv May 06 '20 at 10:57
4

Of course it is a working approach to modify cd's behavior, but I would like to show a more simple solution. In the man bash(1) I found that if an interactive exits it runs ~/.bash_logout if exists. So instead of storing the path at every invocation of cd the last path can be saved at exit.

My ~/.bash_logout is very simple:

echo $PWD >~/.lastdir

And somewhere in my .bashrc I placed this line:

[ -r ~/.lastdir ] && cd $(<~/.lastdir)
Rui F Ribeiro
  • 55,929
  • 26
  • 146
  • 227
TrueY
  • 623
  • 7
  • 8
  • 1
    Just note that `.bash_logout` runs only when `login shells` exit, that's not always the case. – henfiber Jun 23 '15 at 04:46
  • 1
    Alternatively, save the last path when `bash` exits with : `trap "echo $PWD > ~/.lastdir" EXIT"` – henfiber Jun 23 '15 at 05:02
  • @henfiber Thanks for your comments! I think in this case the shell is a login shell, so this will behave properly. On the other hand the `trap` approach is also nice, I like it! – TrueY Jun 23 '15 at 07:18
2

Very often I use multiple terminal windows at once, each with multiple tabs in it. For example: one window for source code development tabs, one window for latex files, one window for R execution and scripting, etc. Within one window, I want a new tabbed terminal to change to the directory which is used last in that particular window (this used to work in the past, but with the new gnome version, somehow it doesn't). The following dirty solution works fine for me. I have put this in .bashrc.

dirfilename="/tmp/.lastdir-$WINDOWID"
[ -r "$dirfilename" ] &&  {
    savdir=`cat $dirfilename`
    cd "$savdir"
}

function cd ()
{
    builtin cd "$@"
    echo $PWD > $dirfilename
}
BartT
  • 31
  • 2
0

In zsh, you can use the hooks:

chpwd_functions=(${chpwd_functions[@]} "function-that-saves-pwd")
HappyFace
  • 1,493
  • 9
  • 21
-1

Paste this on ~/.bashrc, (or ~/.zshrc if you use zsh).

set_working_dir() {
  # All terminals after this command, will be opened in your current directory.
  for var in "$@"
  do
    echo "$var" > ~/.cache/.last_dir 
  done
    if [ $# -eq 0 ]
  then
    pwd > ~/.cache/.last_dir
    fi
  echo '* Working directory saved.'
}
alias sdw='set_working_dir'

Reboot, and you can use it like:

swd

or

swd "/some/directory"

Then launch your terminal like:

nameofyourterminal --working-directory=$(cat ~/.cache/.last_dir)
Adrian Lopez
  • 281
  • 3
  • 10
  • Reboot ? I think there is a lighter alternative like sourcing the resource file again. And I'm not speaking about the fact this script seems to mimic a native behavior in a none working way. – Plup Jul 31 '21 at 19:30