Cygwin终端Bash脚本运行rsync无法找到cygdrive挂载点问题
问题描述
在Windows系统的Cygwin终端中,手动执行如下rsync命令可正常将文件从Windows同步至Linux端:
/usr/bin/rsync -avh --progress --no-whole-file --partial --no-owner --no-group --no-perms --omit-dir-times --log-file=/home/Stefan-Admin/transfer_d.txt /cygdrive/d/* root@172.16.1.224:/mnt/disc_1/drive_d/. > backup_to_d_drive_log.txt
将完全相同的命令写入Cygwin环境下具备rwx权限的Bash脚本(示例命名为do_copy.sh)中执行时出现故障,示例脚本内容如下:
set -e set -x timestart=$(date) /usr/bin/rsync -avh --progress --no-whole-file --partial --no-owner --no-group --no-perms --omit-dir-times --log-file=/home/Stefan-Admin/transfer_d.txt /cygdrive/d/* root@172.16.1.224:/mnt/disc_1/drive_d/. > backup_to_d_drive_log.txt
在Cygwin终端通过bash -f do_copy.sh运行脚本时,rsync报错提示无法找到/cygdrive/d路径,执行输出日志如下:
+ /usr/bin/rsync -avh --progress --no-whole-file --partial --no-owner --no-group --no-perms --omit-dir-times --log-file=/home/Stefan-Admin/transfer_d.txt '/cygdrive/d/*' root@172.16.1.224:/mnt/disc_1/drive_d/. rsync: [sender] link_stat "/cygdrive/d/*" failed: No such file or directory (2) rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1330) [sender=3.2.4dev]
通过df -mh命令可确认/cygdrive/d挂载点确实存在,返回结果如下:
$ df -mh Filesystem Size Used Avail Use% Mounted on D: 1.6T 606G 954G 39% /cygdrive/d $
手动执行rsync可正常运行,但脚本执行时源路径被自动包裹为单引号形式,通配符未正常展开,导致rsync无法识别路径。
故障根因
核心问题出在执行脚本时使用的bash -f参数:
-f是Bash的内置选项,等价于set -o noglob,作用是全局禁用Shell的通配符展开功能- 交互式终端手动执行命令时,Bash默认开启通配符展开,会先把
/cygdrive/d/*中的*替换为D盘下所有文件、子目录的实际路径列表,再将展开后的参数传给rsync,因此命令可正常运行 - 加
-f参数执行脚本时,通配符展开被关闭,/cygdrive/d/*会作为字面字符串直接传递给rsync,rsync会尝试在/cygdrive/d路径下查找名为*的单个文件,自然会返回文件不存在的错误。set -x调试输出中给路径加单引号,就是为了标识该参数是未经过展开的字面量,并非/cygdrive/d挂载点本身不存在。
修复方案
可任选以下一种方案解决问题:
- 去掉执行命令中的
-f参数,直接使用bash do_copy.sh运行脚本。默认启动的Bash会正常开启通配符展开,执行效果和交互式终端手动执行完全一致。 - 如果因特殊需求必须保留
-f参数启动Bash,可在脚本中rsync命令执行前添加一行set +f,临时开启通配符展开,待rsync执行完成后如有需要再通过set -f关闭即可。 - 不依赖Shell的通配符展开能力,直接将目录路径传给rsync,由rsync自行遍历目录下的内容。将源路径从
/cygdrive/d/*修改为/cygdrive/d/,目标路径末尾的/.可简化为标准目录结尾斜杠/即可。这种写法不受noglob模式影响,和原命令同步效果完全一致,还能避免磁盘根目录文件数量过多时,通配符展开触发的"参数列表过长"报错,修改后的rsync命令如下:
/usr/bin/rsync -avh --progress --no-whole-file --partial --no-owner --no-group --no-perms --omit-dir-times --log-file=/home/Stefan-Admin/transfer_d.txt /cygdrive/d/ root@172.16.1.224:/mnt/disc_1/drive_d/ > backup_to_d_drive_log.txt
内容的提问来源于stack exchange,提问作者Stefan
相关产品推荐
相关产品推荐

