Shell脚本切换用户后变量未解析,如何传递变量值?
你遇到的问题本质是Shell引号的变量解析规则在切换用户时搞的鬼:当你用su test2 -c '命令'这种形式时,单引号会强制Shell把内部所有内容原样传递给test2的Shell环境执行——但test2的环境里根本没有$user这个变量,所以它被解析成了空值,最终执行的命令变成了touch /home/test2/.file,自然就生成了错误的.file文件。
根据不同场景,有几种可靠的解决方式:
方式1:改用双引号包裹执行命令
双引号会让当前Shell(test1的Shell)先解析$user变量,再把解析后的完整命令传递给test2执行:
#!/bin/bash user="test1" # 用双引号包裹要执行的命令,让当前Shell先解析变量 su test2 -c "touch /home/test2/$user.file"
这样当前Shell会先把$user替换成test1,传给test2的命令就是touch /home/test2/test1.file,执行后就能生成正确的文件。
方式2:单引号+变量拼接(适合命令内有其他单引号的场景)
如果你的命令里必须用到单引号(比如涉及字符串匹配、转义等),可以把$user部分单独用双引号包裹,和单引号内容拼接起来:
#!/bin/bash user="test1" # 单引号部分原样传递,变量部分由当前Shell解析后拼接 su test2 -c 'touch /home/test2/'"$user"'.file'
这里'touch /home/test2/'是原样传递的字符串,"$user"被当前Shell解析为test1,'.file'也是原样传递,最终组合成正确的命令。
方式3:用sudo替代su(更简洁的写法)
如果你的环境允许使用sudo,这种写法会更直观,同样注意用双引号让当前Shell解析变量:
#!/bin/bash user="test1" # 指定以test2用户身份执行touch命令 sudo -u test2 touch "/home/test2/$user.file"
-u test2指定执行用户,双引号确保$user被正确解析后再传递给touch命令。
如果需要传递多个变量或者更复杂的命令给目标用户,也可以考虑先把变量导出为环境变量,再让目标用户继承:
#!/bin/bash user="test1" export user su test2 -c 'touch /home/test2/$user.file'
不过这种方式需要目标用户的Shell允许继承环境变量(默认大部分是允许的),但相比前面的引号方式可读性稍差,一般推荐前两种方案。
内容的提问来源于stack exchange,提问作者Fazle Rabbi

