Bash脚本中scp从树莓派复制多目录的跨Mac兼容问题
解决Bash脚本中scp多目录复制跨Mac版本失败的问题
基础脚本问题分析
你遇到的核心问题是双引号阻止了Bash的大括号展开。当你把scp源路径用双引号包裹时,{directory1,directory2,directory3}不会被本地Bash解析为多个独立路径,而是作为一个完整的字符串传递给scp,导致远程端找不到这个带大括号的文件。
2016款Mac能运行属于环境巧合(比如旧版本scp或远程shell尝试解析了大括号),但这不是标准行为。正确做法是让本地Bash先完成大括号展开,再传递参数给scp。
修正后的简单脚本:
#!/bin/bash scp -rp pi@192.168.0.163:/home/pi/Documents/data/{directory1,directory2,directory3} .
(移除双引号,让Bash自动将大括号语法展开为多个路径)
实际复杂脚本的问题与修复
你的实际脚本存在两个关键问题:
- getopts处理后位置参数未调整:
getopts会消耗选项和对应参数,处理完后$1并非你传入的IP地址,需要用shift修正位置指针。 - 大括号展开时机错误:通过变量拼接的
{${user_list[@]// /,}}无法被Bash正确展开——变量替换发生在大括号展开之后,且你传入的-u "directory1 directory2"是单个带空格的字符串,不是数组元素。
修正后的可靠脚本
我们用数组存储远程路径,彻底规避大括号展开的环境差异,同时修正参数位置问题:
#!/bin/bash Help() { echo "Usage: $0 -u <directory1> [-u <directory2>]... <raspberrypi_addr>" echo "Example: $0 -u directory1 -u directory2 192.168.0.163" } user_list=() while getopts "hu:" option; do case $option in h) Help exit 0 ;; u) user_list+=("$OPTARG") ;; \?) echo "Error: Invalid option" exit 1 ;; esac done # 跳过已处理的选项参数,让$1指向IP地址 shift $((OPTIND - 1)) # 检查是否传入IP地址 if [ $# -eq 0 ]; then echo "Error: Please provide Raspberry Pi address" Help exit 1 fi RASPBERRYPI_ADDR=$1 RASPBERRYPI_DATA_PATH="/home/pi/Documents/data" RASPBERRYPI_USER_NAME="pi" # 构建每个远程路径的数组 remote_paths=() for dir in "${user_list[@]}"; do remote_paths+=("${RASPBERRYPI_USER_NAME}@${RASPBERRYPI_ADDR}:${RASPBERRYPI_DATA_PATH}/${dir}") done # 执行scp复制 scp -rp "${remote_paths[@]}" .
执行方式
现在需要逐个传入目录参数:
./script.sh -u directory1 -u directory2 192.168.0.163
可选:兼容空格分隔的目录参数
如果你坚持用-u "directory1 directory2"的方式传入,修改getopts的u)分支,将字符串分割为数组:
u) # 把空格分隔的字符串拆分为数组元素 IFS=' ' read -r -a dirs <<< "$OPTARG" user_list+=("${dirs[@]}") ;;
这样就可以继续使用原执行命令:
./script.sh -u "directory1 directory2" 192.168.0.163
内容的提问来源于stack exchange,提问作者IvonChan
相关产品推荐
相关产品推荐

