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.

2
  • Are you using the "tabbed" perl extension of urxvt? Feb 23, 2012 at 18:32
  • No tabs, I'm using new terminals managed by WM
    – Luca
    Feb 23, 2012 at 18:36

8 Answers 8

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

2
  • 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, 2013 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: gist.github.com/jonleighton/1f0b96b49247a07dbaa30fbbe70b34f7 Aug 31, 2019 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"'
4
  • 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, 2012 at 19:12
  • I like that. No disk writes and the only execution takes place when you're about to open the new terminal. Feb 23, 2012 at 19:14
  • The only thing I'd change is to use ( urxvt & ) &>/dev/null instead of just backgrounding. Feb 23, 2012 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, 2012 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.

7
  • PROMPT_COMMAND that's what I was looking for. I will try this solution hoping it doesn't affect performances.
    – Luca
    Feb 23, 2012 at 19:25
  • Well, it is a rather crude way, frankly. Personally, I like Michael's solution best :) Feb 23, 2012 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 Feb 23, 2012 at 19:37
  • It seems that $PWD is evaluated only the first time
    – Luca
    Feb 23, 2012 at 21:25
  • 1
    bugs.launchpad.net/ubuntu/+source/gnome-terminal/+bug/1132700 For gnome-terminal just do: . /etc/profile.d/vte.sh
    – Ajax
    Apr 5, 2015 at 23:20
7

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

3
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)
3
  • 1
    Just note that .bash_logout runs only when login shells exit, that's not always the case.
    – henfiber
    Jun 23, 2015 at 4:46
  • 1
    Alternatively, save the last path when bash exits with : trap "echo $PWD > ~/.lastdir" EXIT"
    – henfiber
    Jun 23, 2015 at 5: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, 2015 at 7: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
}
1
  • This is perfect... wohoo! Thanks. I don't know a lot about hacking bash, but man I'm already loving it... Dec 16, 2016 at 16:25
0

In zsh, you can use the hooks:

chpwd_functions=(${chpwd_functions[@]} "function-that-saves-pwd")
-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)
1
  • 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, 2021 at 19:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .