在 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
语句相匹配是不可能的。要与一个正则表达式匹配,使用支持环顾运算符(如 )的正则表达式会稍微容易一些perl
。zsh
并ksh93
支持这些(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
(如果可以简化的话我不会感到惊讶)。