You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bash脚本中变量无法传递给rsync的问题排查

问题:rsync脚本中输入~作为路径变量时失效的原因

我写了一个用rsync复制文件的简单bash脚本:

#! /bin/bash

read -p "enter src: " sdir
read -p "enter target: " tdir
read -p "enter name of log file: " lfile

current_date=$(date +%Y-%m-%d)

rsync_options="-avb --exclude Documents --exclude Desktop --exclude Music --exclude Downloads --exclude Videos --exclude Backgrounds --exclude Pictures --exclude .cache --exclude .cabal --backup-dir $tdir/current_date --delete"

$(which rsync) $rsync_options $sdir $tdir/$current_date.$lfile >> /home/paul/Documents/logs/backup_$current_date.$lfile

运行脚本时出现以下错误:

paul on arch ~ took 8s
10:07 ❯ backup1.sh
enter src: ~/
enter target: /run/media/paul/7b266343-ee12-4e6b-bff5-77307f299ba0/Vostro/
enter name of log file: home
rsync: [sender] change_dir "/home/paul/~" failed: No such file or directory (2)
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1338) [sender=3.3.0]

直接把脚本里的$sdir替换成实际路径~/时,脚本能正常运行,但用变量传递就不行,其他变量却没问题。我试了在多个目录运行脚本,情况都一样。之后我改写了脚本,这个版本能正常运行:

#! /bin/bash

if [ $# -ne 3 ]
then 
    echo "Usage: backup.sh <source_directory> <target_directory>"
    echo "Please try again."
    exit 1
fi   

if! command -v rsync > /dev/null 2>&1
then echo "This script requires rsync"
    exit 2
fi

current_date=$(date +%Y-%m-%d)

rsync_options="-avb --exclude Documents --exclude Desktop --exclude Music --exclude Downloads --exclude Videos --exclude Backgrounds --exclude Pictures --exclude .cache --exclude .cabal --backup-dir $2/current_date --delete"

$(which rsync) $rsync_options $1 $2/$current_date.$3 >> /home/paul/Documents/logs/backup_$current_date.$3.log

# run this script doing something like: backup.sh /home/paul /run/media/paul/7b266343-ee12-4e6b-bff5-77307f299ba0 paul

原因分析

问题核心在于波浪号~的解析时机:

  • 当你在命令行直接输入~/或者在脚本里硬写~/时,bash会在执行命令前自动把~解析为当前用户的家目录(即/home/paul/)。
  • 但通过read命令读取输入的~/时,~会被当作普通字符存储在变量sdir中,bash不会对变量内的~做二次解析。因此rsync收到的路径是~/,它会将其视为当前工作目录下的子目录~去查找,自然会出现找不到目录的报错。

而修改后的脚本用位置参数$1传递路径时,如果你在命令行输入~/作为参数,bash会在调用脚本前就完成~的解析,$1拿到的是已经转换好的/home/paul/,因此rsync能正常识别路径。

如果想保留交互式输入的版本,可以手动对变量中的~做解析,比如添加以下代码:

read -p "enter src: " sdir
# 解析变量中的~为家目录路径
sdir=$(eval echo "$sdir")

这样用户输入~/时,eval会触发bash对字符串的解析,将~替换为实际家目录路径,变量sdir就能得到正确的路径值。

内容的提问来源于stack exchange,提问作者Matematleta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 06:54:52