安装oh-my-zsh报错could not create work tree dir '/root/.oh-my-zsh'.: Permission denied的原因&解决办法

前言

linux新手可能会通过su方式切换用户,但没有意识到环境变量没有切换,导致一些奇葩问题,这里便是一个例子,值得记录。

笔者在切换linux用户使用ZSH时遇到问题,确切来说是切换用户后安装oh-my-zsh时遇到问题。
问题出现的根本原因在切换用户方式上,我是通过su 某用户切换用户,而这样切换用户,环境变量仍是切换前用户的!

关于切换用户环境变量是否随之切换看这里解析。

  • 熟悉linux的朋友:只需看问题,原因,解决办法即可。
  • 新手:可以看下完整解决过程。个人认为,遇到问题->解决问题的过程才是最重要的,知道问题的答案去理解都不难,关键是由不懂到懂的过程。

问题

背景:linux下,zsh已成功安装,某个用户的oh-my-zsh也已成功安装,能正常使用。

可能,你刚新添加了一个用户,想这个用户也能使用zsh;可能你因某个需求要切换到某个用户,切换后发现其shell不是zsh或用起来不方便,想这个用户也能方便使用zsh。总之,你通过su A用户切换到A用户,然后开始

  1. 安装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
    
  2. 疑似权限问题,你尝试加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相关文件是每个用户独有的,不是所有用户共用一份的。

  • 第一个报错:

    1. 安装脚本install.sh文件内容:判断$ZSH是否有值,有值,访问其指代的目录文件,没问题则打印你已安装;权限问题访问不了则权限错误;无值,则将相关文件安装在~/.oh-my-zsh,并export ZSH=~/.oh.-my-zsh
    2. 通过su切换用户,环境变量并未随之改变$ZSH变量为切换前用户的对应值,以切换前用户为root为例,echo $ZSH,显示/root/.oh-my-zsh

    综上,当前用户并未安装oh-my-zsh,但安装脚本根据前一个用户的$ZSH以为当前用户已安装,但没权限访问,因此报权限错误。

  • 第二个报错:加上sudo后,有了访问/前一个用户家目录/.oh-my-zsh目录的权限,访问发现确实存在,就报已安装,需要删除后才能重新安装。

综上,根本原因是环境变量没有随用户切换而切换

su 用户 :只切换身份

su - 用户 :身份和shell(包含环境变量)都切换

解决办法

对安装oh-my-zsh来说,关键在于$ZSH变量,只要清空之即可,下面两种方式均可:

  1. 手动清空$ZSH变量

    ZSH=
    ## 查看是否清空成功
    echo $ZSH
    
  2. 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的朋友不用往下看了,很啰嗦的~

解决过程

  1. 首先,我是通过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
    
  2. 切换到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
    
  3. 权限问题,加个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.
    
  4. 分析

    难道要删除/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相关文件权限错误。难道问题出在安装指令上?安装指令指定了安装到哪个目录吗?

  5. 分析安装指令,上网查得

    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脚本文件,并没有通过安装指令指定文件安装位置。

  6. 分析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

  7. 再次分析

    按上面的分析,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
    
  8. 解决:

清空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

至此,安装成功,问题解决。

总结

  1. 切换用户

    • su 用户:只切换身份
    • su - 用户:切换身份和shell(保护环境变量)
  2. linux下载安装指令

    • wget:默认只下载,-O 文件名 指定保存文件名,-O -打印文件内容不保存为文件。
    • curl:默认只打印,-O保存为文件
    • 常伴随出现的:sh -c$()
  3. 一点体会:遇到问题,不要躲。

    很早就出现切换用户无法正常使用zsh问题,开始是通过尽量不切换用户来避开它,但到了必须切换时,例如不能通过root用户使用composer…,就很烦,心里不踏实,切换用户后一遇到报错,总会怀疑是否与所切换用户无法正常使用zsh有关。如果总是积累这那么多不确定,往下走,好累!

相关链接

  • linux 中切换用户:su和su -的使用环境变量详解
  • oh-my-zsh下载地址
  • curl和wget的区别和使用

你可能感兴趣的:(linux)