3

I'm regularly downloading files from a remote server, always from the same directory. So I wrote a custom function that I put in my bashrc:

download_from_myserver () {
    for file in "$@"
    do
        rsync myserver:/home/pierre/downloads/"$file" .
    done
}

Right now, the autocompletion works by default with files in the current directory. I would like to change the autocompletion so that bash automatically connects to the server via ssh and autocompletes with files that are in myserver:/home/pierre/downloads/.

In case I'm not being clear, here's an example: let's say I have my_file.txt in the remote directory, I want to be able to do this:

download_from_my_server my_fiTAB
download_from_my_server my_file.txt

How would I do this ?

Notes : I'm already using a password-less connection, rsync and scp autocomplete work well, that's not the issue. I'm using Ubuntu on both machines if that's important.

  • Nit: in "$@" is redundant in this case - for by default loops over the parameters. – l0b0 May 15 '13 at 10:55
3

Edit: Sliced it up some more.

You might find this useful, from Debian Administration: An introduction to bash completion.


Complete script: /some/location/my_ssh_autocomplete_script (only meant as a short starter):

#!/bin/bash

_get_rsync_file_list()
{
    # For test:
    #local -a flist=("foo" "bar")
    #printf "%s " "${flist[@]}"
    # Or:
    ls /tmp

    # For live something in direction of:
    #ssh user@host 'ls /path/to/dir' <-- but not ls for other then dirty testing.
}

_GetOptSSH()
{
    local cur

    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"

    case "$cur" in
    -*)
        COMPREPLY=( $( compgen -W '-h --help' -- "$cur" ) );;
    *)
        # This could be done nicer I guess:
        COMPREPLY=( $( compgen -W "$(_get_rsync_file_list)" -- "$cur" ) );;
    esac

    return 0
}

Download script /some/location/my_ssh_download_script:

#!/bin/bash

server="myserver"
path="/home/pierre/downloads"

download_from_myserver() {
    for file; do
        rsync "$server:$path/$file"
    done
}

case "$1" in
    "-h"|"--help")
        echo "Download files from '$server', path: '$path'" >&2
        exit 0;;
esac

download_from_myserver "$@"

In .bash_aliases:

alias download_from_myserver='/some/location/my_ssh_download_script'

In .bash_completion:

# Source complete script:
if . "/some/location/my_ssh_autocomplete_script" >/dev/null 2>&1; then
    # Add complete function to download alias:
    complete -F _GetOptSSH download_from_myserver
fi
  • "Double quote" every expansion, and anything that could contain a special character, eg. "$var", "$@", "${array[@]}", "$(command)". Use 'single quotes' to make something literal, eg. 'Costs $5 USD'. See <mywiki.wooledge.org/Quotes>, <mywiki.wooledge.org/Arguments> and <wiki.bash-hackers.org/syntax/words>. – Rany Albeg Wein May 15 '13 at 11:56
  • ls is a tool for interactively looking at file information. Its output is formatted for humans and will cause bugs in scripts. Use globs or find instead. Understand why: mywiki.wooledge.org/ParsingLs – Rany Albeg Wein May 15 '13 at 11:57
  • By convention, environment variables (PATH, EDITOR, SHELL, ...) and internal shell variables (BASH_VERSION, RANDOM, ...) are fully capitalized. All other variable names should be lowercase. Since variable names are case-sensitive, this convention avoids accidentally overriding environmental and internal variables. – Rany Albeg Wein May 15 '13 at 11:57
  • Thanks, this solution works really well! I did use find instead of ls, as pointed out by Rany Albeg Wein but that's the only thing I changed. And thank you for the link to debian-administration.org, I already read it but I wasn't handy enough to make good use of it :p – Pierre Mourlanne May 15 '13 at 12:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.