4

I just read the Linux scp command issue question and it reminded me that I regularily forget to specify the colon in the host part of a scp command, and thus copying a file locally instead of copying to a remote host, e.g. I do

scp foo host

instead of

scp foo host:

But I never use scp to copy a file locally. So I wonder if there is a way to make scp fail if both (the source and destination) arguments refer to local files.

3 Answers 3

3

You could write a wrapper function in Bash and name it scp that uses getopts to process the options into a new array leaving the source and destination in the positional parameters, then check those for the presence of "@" and ":" and, if absent, issue an error message. If they're present, then call the real scp using something like command scp "${args[@]}" "$source" "$dest". The command command causes Bash to call the program that's found in the PATH instead of the function by the same name.

Since, at least on my system, scp only supports the short option type, getopts (which also only supports short options) will work fine for this.

The function would look something like this (untested):

scp () {
    # wrapper function to prevent scp of local-only files
    options=":346BCpqrTvc:F:i:J:l:o:P:S:"
    while getopts $options option
    do
        case $option in
            3 | 4 | 6 | B | C | p | q | r | T | v)
                args+=($option)
                ;;
            c | F | i | J | l | o | P | S)
                args+=($option "$OPTARG")
                ;;
            \? ) echo "Unknown option: -$OPTARG" >&2; return 1;;
            :  ) echo "Missing option argument for -$OPTARG" >&2; return 1;;
            *  ) echo "Unimplemented option: -$option" >&2; return 1;;
        esac
    done

    shift $((OPTIND - 1))

    if [[ $1 != *@*:* && $2 != *@*:* ]]
    then
        echo "Local-only copy not permitted"
        echo "to override, use 'command scp ARGS'"
        return 1
    fi
    command scp "${args[@]}" "$1" "$2"
}

The options in this script reflect those accepted by scp at the time of this writing, but they may change over time. That is one of the risks presented by wrapper scripts such as this.

10
  • 2
    Nice trick. However, you should consider naming your wrapper something else than "scp" (maybe "scop"). Overloading well-known commands can be a source of tricky problems because most people/scripts will expect the standard functionality.
    – sleske
    May 17, 2010 at 8:55
  • 2
    Scripts won't use the overloaded function unless you export the function, for example scp () { ... }; export scp May 17, 2010 at 10:49
  • 1
    Oh, @sleske, in addition to the export information in my previous comment, this type of thing is the purpose of the command and builtin commands rather than being just a nice trick. May 17, 2010 at 11:06
  • Interesting info about "command" and "builtin", didn't know that. Still, I'd be wary of overloading scp, if just for the "principle of least surprise". Well, maybe a matter of taste...
    – sleske
    May 17, 2010 at 15:16
  • 1
    @DennisWilliamson Not remove; replace with return. As I wrote in the edit comment, exit will cause the current shell to exit; you need to use return inside functions. See stackoverflow.com/a/4419956/391445 Oct 18, 2022 at 4:49
1

My scp uses the regular cp to copy local files.

Create a script named cp and make sure scp runs with a modified PATH, so it finds the script instead of the real cp.

The script may be like:

#!/bin/sh
echo 'Local copying unsupported!' >&2
exit 1

Save it as ~/.weird-stuff/cp and make it executable. Then create a wrapper named scp that modifies PATH for the real scp. Example wrapper function:

scp () {
PATH="$HOME/.weird-stuff:$PATH" command scp "$@";
}

You may prefer an equivalent wrapper script.

Disadvantage:

  • There is no guarantee that future versions of scp will rely on cp. If scp stops relying on cp (or on PATH to find cp) then the solution will stop working.

Advantage:

  • The solution (unlike this one) does not need to understand options supported by scp. No matter how scp interprets its command line or if anything in this matter changes in the future, the solution will work, if only scp keeps using cp for local copying (and PATH to find cp).
1

Low cost solution: if you are copying always/often from the same directory, and always/often to the same host, just create a fake file with the name of the host and remove all write permissions on it: touch host && chmod ugo-w host. Then your wrong scp command will fail.

You must log in to answer this question.

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