7

In bash is there any way to expand a relative path into an absolute path, perhaps with tab completion?

I ask because sometimes I will search for a file, find it, then vim it:

cd /etc
cd apache2
cd sites-available
vim 000-default

Then I will do some other things and change directories:

cd /tmp
ls
cd ~
ls

Then I'll find that I need to edit the same file again, but it is not possible to use history, (or history search), because the file path is relative.

Current Workaround

If I know I'm going to be reusing a file a lot, after I find it I will grab the full path using something like realpath:

$ realpath 000-default
/etc/apache2/sites-available/000-default
(copy and paste path into next command:)
$ vi /etc/apache2/sites-available/000-default

Caveats

This still requires copying and pasting. I believe there should be an easier way to get a file's full path into my history. What options do I have?

I believe that I have (accidentally) pressed some key combination before that expanded a relative path into a full path. I know in bash you can type:

cd /etc
ls bash_*(control+x *)

and get:

ls bash.bashrc bash_completion bash_completion.d

So is there a way I can expand a relative path into an absolute path, so that I can save operations on a file in my history with that file's full path?

cwd
  • 45,389
  • 2
    You might want to start using pushd and popd so it's easier to go back to a previous directory: http://www.gnu.org/software/bash/manual/bashref.html#The-Directory-Stack – glenn jackman Apr 16 '12 at 16:16
  • @glennjackman - that looks really good. I found this blog and the comments really helpful, too. I'm also looking into cdargs now. Thanks! ps: if nobody else has a better answer just post that and I will accept it. – cwd Apr 16 '12 at 17:37
  • Another possible solution is to leave vim running while youre working around with files, and then bring it back up. You can do this by either doing :sh in vim to start a subshell, and then exit or CTRL+D to get back into vim. Or by doing CTRL+Z in vim to background (STOP) it and then fg to get it back. – phemmer Apr 16 '12 at 22:25

4 Answers4

7

I can't find a good way to do that.

What I do is type $PWD before the file name, then press Tab to expand it. In bash you may need to press Ctrl+Alt+e instead of Tab.

e.g.

vi $PWD/000-default

then

Ctrl+Alt+e

then

Enter

Mikel
  • 57,299
  • 15
  • 134
  • 153
  • damn. this is EXACTLY what I wanted to do. so simple! tab worked for me although ctrl+alt+e did not. I'm using a mac and iTerm2 to ssh to ubuntu. any way to set up something easier than $PWD? (the all caps is kind of cumbersome) – cwd Apr 16 '12 at 23:17
  • update: on mac OS X I realized I can press escape, then control+e to expand the current line even if bash's tab expansion is not enabled. – cwd Mar 12 '13 at 17:35
  • Right. Esc+Ctrl+e is equivalent to Ctrl+Alt+e. Esc sometimes works when Alt (or I guess Option on Mac?) doesn't. – Mikel Mar 13 '13 at 04:02
4

You could use programmable tab completion within bash for this:

function _vim_complete_file() {
    IFS=$'\n' read -d '' -a FILES <<< "$( compgen -A file "${COMP_WORDS[$COMP_CWORD]}" )"
    IFS=$'\n' read -d '' -a COMPREPLY <<< "$( realpath "${FILES[@]}" )"
}

complete -F _vim_complete_file vim

Now if you type vim 000TAB, it will replace 000 with /path/to/000-default.

Explanation
The way this works is that complete -F _vim_complete_file vim tells bash to use the function _vim_complete_file whenever you press TAB on an argument to vim.
The function then runs compgen -A file on the current word the cursor was on when you hit TAB. This returns a list of files matching it.
That list of files is then passed to realpath which generates the fully qualified path. This list is stored as an array in COMPREPLY which the shell looks in for the available completions.

phemmer
  • 71,831
2

You might want to start using pushd and popd so it's easier to go back to a previous directory: http://gnu.org/software/bash/manual/bashref.html#The-Directory-Stack

I saw your comment about cdargs (which I assume is this). For directories that I use frequently, I use an alias or function. For example

alias cgi='pushd /path/to/apache/cgi-bin'

or

docs() { pushd /path/to/apache/docroot/"$1"; }

The 2nd form is useful if there's a parent directory where the subdirs are frequent, then docs foo takes me to /path/to/apache/docroot/foo. The downside is you lose tab completion, but it hasn't been so arduous for me.

glenn jackman
  • 85,964
1

If you are re-editing in Vim, check out :browse oldfiles and :help oldfiles.