往往需要在bash脚本中或者直接在脚本本身添加sudorun命令,但这引发了一系列问题。例如,当使用sudo时,脚本中的~或$HOME指的是用户文件夹的变量。是指向我的真实用户文件夹比如/home/pi,还是指向超级管理员的用户文件夹/root/呢?它实际上指向我们绝对不想要的/root/文件夹。但是很多命令,比如安装程序,都要用到sudo,那怎么办呢?首先说说心得:命令行权限的执行,从性能上来看,分为以下五种情况:admin-manual:普通用户手动输入命令sudo-manual:手动输入命令加上sudoadmin-bash:以普通用户身份执行bash脚本sudo-bash:以root用户身份执行bash脚本sudoroot-any:以root用户身份登录,有很多变量和环境变量在这4种情况下,经常会出现混淆!(混淆指的是我们自己,不是电脑)另外,一个小技巧。我们都知道~变量指向当前用户目录。其实~abc格式变量可以指向指定用户的用户目录。例如,~pi将指向/home/pi,或者~ubuntu将指向/home/ubuntu。理清思路:正常执行./test.sh等脚本是没有问题的,即使脚本中出现sudo如sudoapt-getupdate等sudo也没有问题。也就是说,只有对整个脚本执行sudo,比如sudo./test.sh,才会出现严重的问题!那么假设我的真实用户是pi,HOME目录在/home/pi,现在我需要在sudo./test.sh的执行方式中找出正确的解决方案。以下是脚本中的各种语句和变量以及显示结果:#(不推荐!)$whoami>>>root#与whoami不同的是,它可以指出当前有哪些用户登录了电脑,包括所有本地用户loginsandsshlogins$whoami>>>Somemachinesshowempty>>>Macshows:pittys001Nov2616:57#相当于whoami(不推荐!)$echo$USER>>>root#用户主目录位置(不靠谱,不推荐!)echo$HOME>>>/root$用户主目录位置,相当于$HOME(不推荐!)$echo~>>>/root#直接使用环境变量LOGNAME$echo$LOGNAME>>>root#显式调用环境变量LOGNAME$printenvLOGNAME>>>root#SUDO_USER是root的ENV中的环境变量,#同时普通用户没有env,只有root用户才能显示$sudoecho$SUDO_USER>>>pi#显示调用环境变量SUDO_USER(不推荐!)#从结果可以看出,即使脚本执行为sudo,脚本中是否加入sudo也会不同!$printenvSUDO_USER>>>pi$sudoprintenvSUDO_USER>>>root从上面的测试我们可以看出,如果我们使用sudo来执行bash脚本,很多变量是“不可靠的”。在Stackoverflow中,更一致的趋势是使用$SUDO_USER环境变量。在测试中,确实是最“稳定”的,即在不同的权限和OS系统下都能保持一致(仅限有sudo的系统)。所以现在我们有了用户名,我们可以使用像~pi这样的命令来获取主目录/home/pi,但是!这时候问题又出现了:我们手写的时候可以得到~pi的正确地址,但是脚本不认识~pi是什么,顶多是个字符串,不能像变量一样。既然如此,我们就不能使用~abc的方法了,使用一个老掉牙但绝对不会混淆的方法:直接从/etc/passwd.手动可以直接打开passwd查看,脚本比较麻烦,最方便的是使用系统命令getent,即GetEntries命令,获取指定用户的信息:$getentpasswdpi>>>pi:x:1000:1000:,,,:/home/pi:/bin/bash那么剩下的就是把/home/pi拿出来了,我们用cut就可以轻松的把它拿出来。所以整个过程如下:me=$SUDO_USERmyhome=`getentpasswd$me|cut-d:-f6`成功获取/home/pi!此外,如果脚本未以sudo方式运行怎么办?此时root用户和普通用户的环境变量下是没有SUDO_USER变量的。然后需要加一个判断步骤:me=${SUDO_USER:-$LOGNAME}myhome=`getentpasswd$me|cut-d:-f6`也就是说,如果SUDO_USER为空,$LOGNAME通常用于获取当前用户。为什么使用$LOGNAME而不是$USER?因为USER并不是每个系统都有,而LOGNAME在*nix系统下是有的。更新由于部分OS无法正确获取LOGNAME,统一使用uid方式获取用户路径:HOUSE=`getentpasswd${SUDO_UID:-$(id-u)}|cut-d:-f6`UpdatemacOSwithout/etc/passwd不支持getentpasswd
