I am writing a bash wrapper for scp'ing into and from a certain host with a certain username, like:
johny@bonjour:~/bin$ cat scpphcl
#!/bin/bash
download=false
upload=false
local=""
remote=""
usage()
{
echo "Usage: $0 -d[-u] -l <LocalPath> -r <RemotePath>"
exit 1
}
while getopts "h?dul:r:" opt; do
case "$opt" in
h|\?)
usage
;;
d)
download=true
upload=false
;;
u)
download=false
upload=true
;;
l)
local=$OPTARG
;;
r)
remote=$OPTARG
;;
esac
done
if [[ -z $local || -z $remote ]]; then
echo "Need to provide local and remote path."
usage
fi
if $download; then
scp somebody@somehost:"$remote" $local
elif $upload; then
scp $local somebody@somehost:"$remote"
else
echo "Neither download nor upload?"
exit 1
fi
if [[ $? -ne 0 ]]; then
echo "Something wrong happened in the scp process."
exit 1
fi
exit 0
It works well with the usual filenames, but if there is any wildcard in the local filename field, it will not work right.
johny@bonjour:~/test$ scpphcl -u -l * -r /u/somebody/temp
Need to provide local and remote path.
Usage: /Users/johny/bin/scpphcl -d[-u] -l <LocalPath> -r <RemotePath>
There is a walkaround, using sinqle quotes around the local file argument if there is a wildcard in it:
johny@bonjour:~/test$ scpphcl -u -l '*' -r /u/somebody/temp
But even this walkaround will not work, if the command is issued outside the folder test
:
johny@bonjour:~/test$ cd ..
johny@bonjour:~$ scpphcl -u -l 'test/*' -r /u/somebody/temp
This doesn't work and will hang in the scp process.
Any help in how to pass the wildcard in local filenames with the bash wrapper?
It's probably best not to require your users to quote wildcard patterns. I'd instead change the interface of your program to accept any number of local paths, after the option arguments:
echo "Usage: $0 [-d|-u] [-r <RemotePath>] <LocalPath>..."
When reading options, consume them with shift
:
while getopts "h?dur:" opt; do
case "$opt" in
h|\?)
usage
exit 0
;;
d)
download=true
upload=false
;;
u)
download=false
upload=true
;;
r)
remote="$OPTARG"
;;
*)
usage >&2
exit 1
;;
esac
done
shift $((OPTIND-1))
Now the remaining positional arguments are the local filenames (and can be accessed with "$@"
- note the all-important double-quotes there):
if test -z "$*" # no LocalPath arguments!
then usage >&2; exit 1
elif $download
then exec scp somebody@somehost:"$remote" "$@"
elif $upload
then exec scp "$@" somebody@somehost:"$remote"
fi