How can I expand a relative path at the command line, with tab completion?

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?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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

Method 2

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.

Method 3

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.

Method 4

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


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x