远程主机上位置路径的通配符

远程主机上位置路径的通配符

在 Bash 中,我需要检查字符串中包含的路径是否指向远程位置。以下不起作用 -some code不会被执行。似乎我缺少有关通配符如何与test( [) 命令配合使用的一些信息,但我不知道是什么。手册页对我没有帮助。我做错了什么?我应该如何解决这个问题?

path="user@host:/home/user"
if [ "$path" == ?*"@"?*":"?* ]; then
  some code
fi

答案1

[命令是一个命令,并且被解析为任何其他命令。这意味着:

[ "$path" == ?*"@"?*":"?* ]

?*"@"?*":"?*视为一个 glob,因此将扩展到当前目录中与该模式匹配的文件列表(就像扩展到当前目录中的文件*.txt列表一样)。txt

即使你写的是:

[ "$path" == '?*@?*:?*' ]

为了防止通配符,这将不起作用,因为命令的==运算符(非标准版本)只是一个字符串相等运算符,而不是模式匹配运算符。=[

要进行模式匹配,您可以使用ksh-style[[ x = pattern ]]模式匹配运算符,它还bash支持zsh

path="user@host:/home/user"
if [[ "$path" = ?*@?*:* ]]; then
  some code
fi

或者更好的是,使用 POSIX/Bournesh case构造:

case $path in
  ?*@?*:*) some code
esac

这样,您甚至不需要安装bash,就可以使用系统的标准sh来解释您的脚本。

请注意,这user@host:/home/user也是有效的当地的path (try mkdir -p user@host:/home/user) 虽然使用scp,您需要将其传递为,./user@host:/home/user以便它不被视为远程路径。因此,您可能需要将测试细化为:

case ${path%%@?*:*} in
  (*/* | "$path" | "") echo not a remote path;;
  (*) echo remote path;;
esac

这样./x@y:z就不会被视为远程路径。

这仍然不足以执行与scp确定路径是否远程相同的操作。看着OpenSSHscp代码,如果路径不是以 开头,:并且包含左侧带有:no且不在 a​​ 内的路径,则该路径是远程路径(对于像 之类的 IPv6 地址。除了这些仅在主机位置(在开头或例如,下面的)是远程路径(尽管显然用户和主机部分为空,这可能无法正常工作)和(留给不在中间的)或本地路径(在里面)。/[...][::1][...]@x:@:user@[::1/64]:/x/:[...][foo@bar:/path:[...]

将其与一个 POSIXcase语句相匹配是不可能的。要与一个正则表达式匹配,使用支持环顾运算符(如 )的正则表达式会稍微容易一些perlzshksh93支持这些(zsh使用 PCRE 库,ksh93使用它自己的实现)。

  • zsh

    set -o rematchpcre
    remote='^(?!:)(?:(?!\[)[^/:]*@)?(?:\[(?:(?!]:)[^/])*\]|(?!\[)[^/:]*):'
    if [[ $path =~ $remote ]]; then
      some code
    fi
    
  • ksh93

    remote='(?P:^(?!:)(?:(?!\[)[^/:]*@)?(?:\[(?:(?!]:)[^/])*\]|(?!\[)[^/:]*):)'
    if [[ $path =~ $remote ]]; then
      some code
    fi
    

(如果可以简化的话我不会感到惊讶)。

相关内容