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

Bash中su命令导致SCP命令变量丢失问题排查

问题

在Ubuntu 18.04.6 LTS系统(Bash 4.4.20(1))中,运行脚本通过su切换到用户me执行SCP时出现变量未解析的错误,但直接在命令行执行相同逻辑的命令却能正常工作。

脚本用于从远程主机拉取文件到本地/tmp,由于root无法无密码SCP,只能切换到有权限的me用户执行。脚本内容如下:

#!/bin/bash

writeCmd() { printf '%q ' "$@"; printf '\n'; }

printf -v date '%(%Y%m%d)T' -1

user=me
host=10.10.10.100
file=myfile
target_dir=/path/to/dir/$date

# 打印要执行的命令
writeCmd su - me -c 'scp -C me@$host:/$target_dir/$file.txt /tmp/.'
su - me -c 'scp -C me@$host:/$target_dir/$file.txt /tmp/.'

执行后输出的命令完全乱掉,变量未被解析:

su - me -c scp-Cme@10.10.10.100://.txt/tmp/.
原因

问题出在单引号的使用:

  • Bash中,单引号包裹的内容会被当作纯字符串,当前shell不会解析其中的变量($host、$target_dir、$file)。
  • 当su - me -c '...'执行时,切换到me用户的shell后,这个shell里并没有定义host、target_dir这些变量,所以变量展开后变成空值,导致SCP命令的路径拼接混乱,出现//.txt这种错误格式。

而直接在命令行执行时,你大概率是用双引号或者未加引号让变量被当前shell解析,所以能正常工作。

解决方法

把su -c后的单引号换成双引号,让当前shell先解析变量,再把完整的SCP命令传给me用户执行:

修改后的脚本关键部分:

writeCmd su - me -c "scp -C me@$host:/$target_dir/$file.txt /tmp/."
su - me -c "scp -C me@$host:/$target_dir/$file.txt /tmp/."

这样当前shell会先将$host、$target_dir、$file替换为实际定义的值,生成完整的SCP命令后,再交给me用户的shell执行,就能正常拉取文件了。

如果你的变量中包含空格、特殊字符等需要转义的内容,可以考虑用printf %q来安全转义,或者将变量通过环境变量传递给su后的shell,但上述双引号的方式在大多数场景下已经足够解决问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:36:53