前言
linux新手可能会通过su
方式切换用户,但没有意识到环境变量没有切换,导致一些奇葩问题,这里便是一个例子,值得记录。
笔者在切换linux用户使用ZSH
时遇到问题,确切来说是切换用户后安装oh-my-zsh
时遇到问题。
问题出现的根本原因在切换用户方式上,我是通过su 某用户
切换用户,而这样切换用户,环境变量仍是切换前用户的!
关于切换用户环境变量是否随之切换看这里解析。
- 熟悉linux的朋友:只需看问题,原因,解决办法即可。
- 新手:可以看下完整解决过程。个人认为,遇到问题->解决问题的过程才是最重要的,知道问题的答案去理解都不难,关键是由不懂到懂的过程。
问题
背景:linux下,zsh已成功安装,某个用户的oh-my-zsh也已成功安装,能正常使用。
可能,你刚新添加了一个用户,想这个用户也能使用zsh;可能你因某个需求要切换到某个用户,切换后发现其shell不是zsh或用起来不方便,想这个用户也能方便使用zsh。总之,你通过su A用户
切换到A用户,然后开始
-
安装
oh-my-zsh
,执行指令sh -c "$(wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)"
遇到类似以下报错:
Cloning Oh My Zsh... fatal: could not create work tree dir '/root/.oh-my-zsh'.: Permission denied Error: git clone of oh-my-zsh repo failed
-
疑似权限问题,你尝试加
sudo
解决sudo sh -c "$(wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)"
然后报已安装错误
You already have Oh My Zsh installed. You'll need to remove /root/.oh-my-zsh if you want to re-install.
原因
首先,明确一点:oh-my-zsh
相关文件是每个用户独有的,不是所有用户共用一份的。
-
第一个报错:
- 安装脚本
install.sh
文件内容:判断$ZSH
是否有值,有值,访问其指代的目录文件,没问题则打印你已安装;权限问题访问不了则权限错误;无值,则将相关文件安装在~/.oh-my-zsh
,并export ZSH=~/.oh.-my-zsh
。 - 通过
su
切换用户,环境变量并未随之改变,$ZSH
变量为切换前用户的对应值,以切换前用户为root为例,echo $ZSH
,显示/root/.oh-my-zsh
。
综上,当前用户并未安装
oh-my-zsh
,但安装脚本根据前一个用户的$ZSH
以为当前用户已安装,但没权限访问,因此报权限错误。 - 安装脚本
-
第二个报错:加上sudo后,有了访问
/前一个用户家目录/.oh-my-zsh
目录的权限,访问发现确实存在,就报已安装,需要删除后才能重新安装。
综上,根本原因是环境变量没有随用户切换而切换。
su 用户 :只切换身份
su - 用户 :身份和shell(包含环境变量)都切换
解决办法
对安装oh-my-zsh
来说,关键在于$ZSH
变量,只要清空之即可,下面两种方式均可:
-
手动清空
$ZSH
变量ZSH= ## 查看是否清空成功 echo $ZSH
-
ctrl + d
退回能最开始的用户,通过su -
切换su - 期望用户 ## 查看一下 echo $ZSH
然后执行下载安装
sh -c "$(wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)"
输出以下内容,表示成功
__ __
____ / /_ ____ ___ __ __ ____ _____/ /_
/ __ \/ __ \ / __ `__ \/ / / / /_ / / ___/ __ \
/ /_/ / / / / / / / / / / /_/ / / /_(__ ) / / /
\____/_/ /_/ /_/ /_/ /_/\__, / /___/____/_/ /_/
/____/ ....is now installed!
Please look over the ~/.zshrc file to select plugins, themes, and options.
p.s. Follow us at https://twitter.com/ohmyzsh.
p.p.s. Get stickers and t-shirts at https://shop.planetargon.com.
安装成功后,查看$ZSH
的值,验证上述说法
echo $ZSH
## 输出
/home/当前用户家目录/.oh-my-zsh
熟悉linux的朋友不用往下看了,很啰嗦的~
解决过程
-
首先,我是通过root用户连接到服务器的,安装,使用zsh,oh-my-zsh一切顺利,因某个需求要切换到test用户
su test
,发现没有zsh效果,echo $SHELL
,是bash…,原来是忘了修改test用户的默认shell,切换回root用户,
vim /etc/passwd
,修改并保存test:x:1007:1007::/home/test:/bin/bash ## 改为 test:x:1007:1007::/home/test:/bin/zsh
-
切换到test用户,
echo $SHELL
,变为zsh了。然而一点也不方便,并且没有炫酷的终端效果——颜色变化,猜测是没有oh-my-zsh
,心想,原来好用的是oh-my-zsh!安装之,一条命令而已sh -c "$(wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)"
然后就报权限错误:
Cloning Oh My Zsh... fatal: could not create work tree dir '/root/.oh-my-zsh'.: Permission denied Error: git clone of oh-my-zsh repo failed
-
权限问题,加个sudo看看吧
sudo sh -c "$(wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)"
提示我test用户不在sudo列表里,不能使用sudo,
test is not in the sudoers file. This incident will be reported.
添加之
su root ## 切换到root用户 chmod u+w /etc/sudoers ## 添加sudoers文件所属用户的写入权限 vim /etc/sudoers ## 添加如下内容 test ALL=(ALL) ALL chmod u-w /etc/sudoers ## 添加完成删除写入权限,保证安全
再执行一次安装指令。报oh-my-zsh已安装…,额,已安装你倒是让我test用户使用啊…
You already have Oh My Zsh installed. You'll need to remove /root/.oh-my-zsh if you want to re-install.
-
分析
难道要删除
/root/.oh-my-zsh
?,但删除了root用户怎么使用呢?首先要确认
oh-my-zsh
相关文件像指令一样给所有用户共用,还是像配置文件一样每个用户独有?- 如果是共用的,不应该默认安装在
root
家目录下啊(我没改任何配置),其它用户去访问root
家目录,即使放开权限能行,始终是不合适的(何况我试过把/root/.oh-my-zsh权限设为777
,还是不行)。 - 得出结论:
oh-my-zsh
相关文件是每个用户独有的。 - 结论推导是:在test用户下安装
oh-my-zsh
,会在test用户家目录添加oh-my-zsh
相关文件。
但现在的确是在test用户下,执行github上
oh-my-zsh
给的安装指令,却报root家目录下oh-my-zsh
相关文件权限错误。难道问题出在安装指令上?安装指令指定了安装到哪个目录吗? - 如果是共用的,不应该默认安装在
-
分析安装指令,上网查得
sh -c "$(wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)"
-
sh命令
是shell命令语言解释器,-c
指从-c
后的字符串读取; -
$()
简单理解是将执行括号里代码得到的结果返回 -
wget
是下载 指定url的文件(默认指下载,不打印,与curl相反),-O
后接保存到本地的文件名,用-O -
表示将文件内容打印,不保存到本地文件通过与curl比较,更好理解wget使用,链接
最终得到的就是执行了
install.sh
脚本文件,并没有通过安装指令指定文件安装位置。 -
-
分析
install.sh
脚本下载
install.sh
文件来看看内容吧,shell脚本,也是代码而已。wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh vim install.sh
太大段就不全贴上来了,根据报错
Error: git clone of oh-my-zsh repo failed
,在install.sh
搜索到env git clone --depth=1 https://github.com/robbyrussell/oh-my-zsh.git $ZSH || { printf "Error: git clone of oh-my-zsh repo failed\n" exit 1 }
再搜一下,
You already have Oh My Zsh installed.
,内容如下if [ -d "$ZSH" ]; then printf "${YELLOW}You already have Oh My Zsh installed.${NORMAL}\n" printf "You'll need to remove $ZSH if you want to re-install.\n" exit fi
都有
$ZSH
变量!且文件中多次出现$ZSH
-
再次分析
按上面的分析,
oh-my-zsh
相关文件是每个用户独有的,那么- 安装脚本理应根据当前用户是谁,来把相关文件安装到谁的家目录;
- 如果当前用户已安装,安装脚本能识别出来,要求他删除后才能再次安装。
经查看,
install.sh
脚本的内容正是如此,具体到安装脚本通过什么来识别,就是$ZSH
变量,如果$ZSH
为空,文件内容如下:if [ ! -n "$ZSH" ]; then ZSH=~/.oh-my-zsh fi ## 把ZSH设为环境变量了 export ZSH=$ZSH
如果
$ZSH
有值,则输出已安装,要先删除$ZSH
指代的文件才能再次安装。到这里,就很明显了,根据报错提示,test用户的
$ZSH
变量是/root/.oh-my-zsh
,查看一下,确实是这样。echo $ZSH /root/.oh-my-zsh
-
解决:
清空ZSH变量,执行下载安装命令,安装成功后,查看$ZSH
变量
ZSH=
sh -c "$(wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)"
echo $ZSH
## 显示
/home/test/.oh-my-zsh
至此,安装成功,问题解决。
总结
-
切换用户
su 用户
:只切换身份su - 用户
:切换身份和shell(保护环境变量)
-
linux下载安装指令
wget
:默认只下载,-O 文件名
指定保存文件名,-O -
打印文件内容不保存为文件。curl
:默认只打印,-O
保存为文件- 常伴随出现的:
sh -c
,$()
-
一点体会:遇到问题,不要躲。
很早就出现切换用户无法正常使用
zsh
问题,开始是通过尽量不切换用户来避开它,但到了必须切换时,例如不能通过root用户使用composer…,就很烦,心里不踏实,切换用户后一遇到报错,总会怀疑是否与所切换用户无法正常使用zsh
有关。如果总是积累这那么多不确定,往下走,好累!