【问题标题】:Pass wildcard to scp in a wrapper bash script在包装器 bash 脚本中将通配符传递给 scp
【发布时间】:2018-02-27 15:14:05
【问题描述】:

我正在编写一个 bash 包装器,用于 scp'ing 进出具有特定用户名的特定主机,例如:

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

它适用于通常的文件名,但如果本地文件名字段中有任何通配符,它​​将无法正常工作。

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>

有一个解决方法,如果其中有通配符,则在本地文件参数周围使用单引号:

johny@bonjour:~/test$ scpphcl -u -l '*' -r /u/somebody/temp

但是,如果在文件夹 test 之外发出命令,即使这种解决方法也不起作用:

johny@bonjour:~/test$ cd ..
johny@bonjour:~$ scpphcl -u -l 'test/*' -r /u/somebody/temp

这不起作用,会挂在 scp 进程中。

对如何使用 bash 包装器在本地文件名中传递通配符有任何帮助吗?

【问题讨论】:

  • 您可能需要转义通配符以使其远程扩展而在本地
  • @Inian scpphcl -u -l 'test/\*' -r /u/somebody/tempscpphcl -u -l test/\* -r /u/somebody/temp 都不起作用。
  • 您也需要引用"$OPTARG"(因此)。还有"$local""$remote"。只要正确引用,无处不在。实际上,你想要local=($OPTARG),然后在命令中使用"${local[@]}"。但可以叫它别的名字——local 是一个 Bash 关键字。
  • @TobySpeight 非常感谢你,托比。有用。另外,感谢您建议为本地路径指定 local 以外的名称。我不知道这是一个 bash 关键字。您能否将您的评论放入答案部分,以便我将其标记为解决方案?如果您添加一些解释会更好。我猜localfile=($OPTARG) 可能将通配符扩展视为一个数组。后来在scp命令中使用的时候,是${localfile[@]}这个数组解引用的方式吗?
  • 是的,这是一个数组。扩展数组的方式是"${localfile[@]}"(那些双引号很重要!)。

标签: bash scp wildcard-expansion


【解决方案1】:

最好不要要求您的用户引用通配符模式。在选项参数之后,我会更改程序的接口以接受 任意数量 的本地路径:

echo "Usage: $0 [-d|-u] [-r <RemotePath>] <LocalPath>..."

阅读选项时,使用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))

现在剩下的位置参数是本地文件名(可以使用"$@" 访问 - 请注意那里最重要的双引号):

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

【讨论】:

  • 完美解决方案!更简洁,更人性化!非常感谢,托比!
  • 另一个问题:使用execscp,而不是像以前那样直接调用它有什么好处?
  • 它节省了一个分叉 - 但确实意味着你之后不会做任何事情(所以你的有用的“出错了”消息不会被显示 - 我足够坚强@987654328 @ 自己的错误消息就足够了,但您的用户可能会有所不同)。另一个优点是,当退出状态很重要时,您的用户会直接获得该状态(而不是像您的版本那样只是 01 - 您必须做一些工作来保留状态代码)。
猜你喜欢
  • 2012-11-09
  • 2021-03-13
  • 1970-01-01
  • 1970-01-01
  • 2017-07-13
  • 1970-01-01
  • 2011-10-18
  • 2019-02-08
  • 1970-01-01
相关资源
最近更新 更多