远程执行test -e时,如何用通配符*检查目录是否存在文件?
问题原因
当你设置$file为/tmp/*时,本地Shell会先对通配符*进行展开,把它替换成本地/tmp目录下的所有文件名(若本地/tmp存在文件),再将这些文件名作为参数传递给远程的test -e命令。而test -e仅支持单个路径参数,多参数输入就会触发bash: test: too many arguments错误。
能否将
*与test -e配合使用? 直接用test -e /tmp/*的方式不可行,但可以通过让远程Shell处理通配符,并调整判断逻辑来实现你“检查目录中是否存在任何文件”的需求。
具体解决方法
方法1:用ls判断远程通配符匹配结果
通过单引号包裹远程命令,阻止本地Shell解析通配符,让远程Shell处理*,并借助ls的退出码判断是否有匹配文件:
if ssh user@$host 'ls -d /tmp/* >/dev/null 2>&1'; then # /tmp目录下存在文件时执行的代码块 fi
ls -d /tmp/*会列出所有匹配的文件/目录,重定向输出到空是为了避免冗余内容干扰;- 只要有至少一个匹配项,
ls的退出码为0,条件成立。
方法2:结合test的远程通配符判断逻辑
如果一定要基于test语法实现,可以在远程Shell中先展开通配符,再判断匹配数量:
if ssh user@$host 'shopt -s nullglob; set -- /tmp/*; [ $# -gt 0 ]'; then # /tmp目录下存在文件时执行的代码块 fi
shopt -s nullglob:若通配符无匹配文件,直接移除该参数(而非保留原字符串);set -- /tmp/*:将通配符展开后的文件列表设为位置参数;[ $# -gt 0 ]:判断位置参数数量是否大于0,即是否存在匹配文件。
方法3:针对本地变量$file的通用写法
如果$file是本地变量,需传递到远程执行,要确保通配符在远程展开,同时避免本地Shell解析:
file="/tmp/*" if ssh user@$host "shopt -s nullglob; set -- '$file'; [ \$# -gt 0 ]"; then # 执行代码块 fi
- 用双引号包裹远程命令,给
$file加单引号防止本地展开; $#前加反斜杠转义,避免本地Shell解析该变量。
补充:更简洁的目录非空判断
如果你的需求只是检查目录是否非空(包含文件或子目录),可以用更直接的写法:
if ssh user@$host '[ -n "$(ls -A /tmp)" ]'; then # 目录非空时执行的代码块 fi
ls -A会列出目录下所有非隐藏文件/目录(不含.和..),若结果非空则说明目录有内容。
内容的提问来源于stack exchange,提问作者Nullpointer
相关产品推荐
相关产品推荐

