zsh+ohmyzsh+powerlevel9k:发出“sudo -s”时完成停止工作

zsh+ohmyzsh+powerlevel9k:发出“sudo -s”时完成停止工作

我在 MacOS High Sierra 上使用 zsh 和 ohmyzsh(带有 powerlevel9k 主题)时遇到了奇怪的问题。

安装 ohmyzsh 后,在发布时sudo -s会收到一些令人讨厌的奇怪脚本输出。并且所有补全功能都停止工作。完全相同的配置在 Linux 上完全按预期工作。

它看起来是这样的:

user@host% sudo -s

bracketed-paste-magic () {
    # undefined
    builtin autoload -XUz
}
colors () {
    emulate -L zsh
    typeset -Ag color colour
    color=(00 none 01 bold 02 faint 22 normal 03 standout 23 no-standout 04 underline 24 no-underline 05 blink 25 no-blink 07 reverse 27 no-reverse 08 conceal 28 no-conceal 30 black 40 bg-black 31 red 41 bg-red 32 green 42 bg-green 33 yellow 43 bg-yellow 34 blue 44 bg-blue 35 magenta 45 bg-magenta 36 cyan 46 bg-cyan 37 white 47 bg-white 39 default 49 bg-default)
    local k
    for k in ${(k)color}
    do
        color[${color[$k]}]=$k
    done
    for k in ${color[(I)3?]}
    do
        color[fg-${color[$k]}]=$k
    done
    color[grey]=${color[black]}
    color[fg-grey]=${color[grey]}
    color[bg-grey]=${color[bg-black]}
    colour=(${(kv)color})
    local lc=$'\e[' rc=m
    typeset -Hg reset_color bold_color
    reset_color="$lc${color[none]}$rc"
    bold_color="$lc${color[bold]}$rc"
    typeset -AHg fg fg_bold fg_no_bold
    for k in ${(k)color[(I)fg-*]}
    do
        fg[${k#fg-}]="$lc${color[$k]}$rc"
        fg_bold[${k#fg-}]="$lc${color[bold]};${color[$k]}$rc"
        fg_no_bold[${k#fg-}]="$lc${color[normal]};${color[$k]}$rc"
    done
    typeset -AHg bg bg_bold bg_no_bold
    for k in ${(k)color[(I)bg-*]}
    do
        bg[${k#bg-}]="$lc${color[$k]}$rc"
        bg_bold[${k#bg-}]="$lc${color[bold]};${color[$k]}$rc"
        bg_no_bold[${k#bg-}]="$lc${color[normal]};${color[$k]}$rc"
    done
}
compdump () {
    # undefined
    builtin autoload -XUz
}
compinit () {
    emulate -L zsh
    setopt extendedglob
    typeset _i_dumpfile _i_files _i_line _i_done _i_dir _i_autodump=1
    typeset _i_tag _i_file _i_addfiles _i_fail=ask _i_check=yes _i_name
    while [[ $# -gt 0 && $1 = -[dDiuC] ]]
    do
        case "$1" in
            (-d) _i_autodump=1
                shift
                if [[ $# -gt 0 && "$1" != -[dfQC] ]]
                then
                    _i_dumpfile="$1"
                    shift
                fi ;;
            (-D) _i_autodump=0
                shift ;;
            (-i) _i_fail=ign
                shift ;;
            (-u) _i_fail=use
                shift ;;
            (-C) _i_check=
                shift ;;
        esac
    done
    typeset -gHA _comps _services _patcomps _postpatcomps
    typeset -gHA _compautos
    typeset -gHA _lastcomp
    if [[ -n $_i_dumpfile ]]
    then
        typeset -g _comp_dumpfile="$_i_dumpfile"
    else
        typeset -g _comp_dumpfile="${ZDOTDIR:-$HOME}/.zcompdump"
    fi
    typeset -gHa _comp_options
    _comp_options=(bareglobqual extendedglob glob multibyte multifuncdef nullglob rcexpandparam unset NO_allexport NO_aliases NO_cshnullglob NO_cshjunkiequotes NO_errexit NO_errreturn NO_globassign NO_globsubst NO_histsubstpattern NO_ignorebraces NO_ignoreclosebraces NO_kshglob NO_ksharrays NO_kshtypeset NO_markdirs NO_octalzeroes NO_posixbuiltins NO_posixidentifiers NO_shwordsplit NO_shglob NO_warnnestedvar NO_warncreateglobal)
    typeset -gH _comp_setup='local -A _comp_caller_options;
             _comp_caller_options=(${(kv)options[@]});
             setopt localoptions localtraps localpatterns ${_comp_options[@]};
             local IFS=$'\'\ \\t\\r\\n\\0\'';
             builtin enable -p \| \~ \( \? \* \[ \< \^ \# 2>&-;
             exec </dev/null;
             trap - ZERR;
             local -a reply;
             local REPLY;
             local REPORTTIME;
             unset REPORTTIME'
    typeset -ga compprefuncs comppostfuncs
    compprefuncs=()
    comppostfuncs=()
    : $funcstack
    compdef () {
        local opt autol type func delete eval new i ret=0 cmd svc
        local -a match mbegin mend
        emulate -L zsh
        setopt extendedglob
        if (( ! $# ))
        then
            print -u2 "$0: I need arguments"
            return 1
        fi
        while getopts "anpPkKde" opt
        do
            case "$opt" in
                (a) autol=yes  ;;
                (n) new=yes  ;;
                ([pPkK]) if [[ -n "$type" ]]
                    then
                        print -u2 "$0: type already set to $type"
                        return 1
                    fi
                    if [[ "$opt" = p ]]
                    then
                        type=pattern
                    elif [[ "$opt" = P ]]
                    then
                        type=postpattern
                    elif [[ "$opt" = K ]]
                    then
                        type=widgetkey
                    else
                        type=key
                    fi ;;
                (d) delete=yes  ;;
                (e) eval=yes  ;;
            esac
        done
        shift OPTIND-1
        if (( ! $# ))
        then
            print -u2 "$0: I need arguments"
            return 1
        fi
        if [[ -z "$delete" ]]
        then
            if [[ -z "$eval" ]] && [[ "$1" = *\=* ]]
            then
                while (( $# ))
                do
                    if [[ "$1" = *\=* ]]
                    then
                        cmd="${1%%\=*}"
                        svc="${1#*\=}"
                        func="$_comps[${_services[(r)$svc]:-$svc}]"
                        [[ -n ${_services[$svc]} ]] && svc=${_services[$svc]}
                        [[ -z "$func" ]] && func="${${_patcomps[(K)$svc][1]}:-${_postpatcomps[(K)$svc][1]}}"
                        if [[ -n "$func" ]]
                        then
                            _comps[$cmd]="$func"
                            _services[$cmd]="$svc"
                        else
                            print -u2 "$0: unknown command or service: $svc"
                            ret=1
                        fi
                    else
                        print -u2 "$0: invalid argument: $1"
                        ret=1
                    fi
                    shift
                done
                return ret
            fi
            func="$1"
            [[ -n "$autol" ]] && autoload -Uz "$func"
            shift
            case "$type" in
                (widgetkey) while [[ -n $1 ]]
                    do
                        if [[ $# -lt 3 ]]
                        then
                            print -u2 "$0: compdef -K requires <widget> <comp-widget> <key>"
                            return 1
                        fi
                        [[ $1 = _* ]] || 1="_$1"
                        [[ $2 = .* ]] || 2=".$2"
                        [[ $2 = .menu-select ]] && zmodload -i zsh/complist
                        zle -C "$1" "$2" "$func"
                        if [[ -n $new ]]
                        then
                            bindkey "$3" | IFS=$' \t' read -A opt
                            [[ $opt[-1] = undefined-key ]] && bindkey "$3" "$1"
                        else
                            bindkey "$3" "$1"
                        fi
                        shift 3
                    done ;;
                (key) if [[ $# -lt 2 ]]
                    then
                        print -u2 "$0: missing keys"
                        return 1
                    fi
                    if [[ $1 = .* ]]
                    then
                        [[ $1 = .menu-select ]] && zmodload -i zsh/complist
                        zle -C "$func" "$1" "$func"
                    else
                        [[ $1 = menu-select ]] && zmodload -i zsh/complist
                        zle -C "$func" ".$1" "$func"
                    fi
                    shift
                    for i
                    do
                        if [[ -n $new ]]
                        then
                            bindkey "$i" | IFS=$' \t' read -A opt
                            [[ $opt[-1] = undefined-key ]] || continue
                        fi
                        bindkey "$i" "$func"
                    done ;;
                (*) while (( $# ))
                    do
                        if [[ "$1" = -N ]]
                        then
                            type=normal
                        elif [[ "$1" = -p ]]
                        then
                            type=pattern
                        elif [[ "$1" = -P ]]
                        then
                            type=postpattern
                        else
                            case "$type" in
                                (pattern) if [[ $1 = (#b)(*)=(*) ]]
                                    then
                                        _patcomps[$match[1]]="=$match[2]=$func"
                                    else
                                        _patcomps[$1]="$func"
                                    fi ;;
                                (postpattern) if [[ $1 = (#b)(*)=(*) ]]
                                    then
                                        _postpatcomps[$match[1]]="=$match[2]=$func"
                                    else
                                        _postpatcomps[$1]="$func"
                                    fi ;;
                                (*) if [[ "$1" = *\=* ]]
                                    then
                                        cmd="${1%%\=*}"
                                        svc=yes
                                    else
                                        cmd="$1"
                                        svc=
                                    fi
                                    if [[ -z "$new" || -z "${_comps[$1]}" ]]
                                    then
                                        _comps[$cmd]="$func"
                                        [[ -n "$svc" ]] && _services[$cmd]="${1#*\=}"
                                    fi ;;
                            esac
                        fi
                        shift
                    done ;;
            esac
        else
            case "$type" in
                (pattern) unset "_patcomps[$^@]" ;;
                (postpattern) unset "_postpatcomps[$^@]" ;;
                (key) print -u2 "$0: cannot restore key bindings"
                    return 1 ;;
                (*) unset "_comps[$^@]" ;;
            esac
        fi
    }
    typeset _i_wdirs _i_wfiles
    _i_wdirs=()
    _i_wfiles=()
    autoload -Uz compaudit
    if [[ -n "$_i_check" ]]
    then
        typeset _i_q
        if ! eval compaudit
        then
            if [[ -n "$_i_q" ]]
            then
                if [[ "$_i_fail" = ask ]]
                then
                    if ! read -q "?zsh compinit: insecure $_i_q, run compaudit for list.
Ignore insecure $_i_q and continue [y] or abort compinit [n]? "
                    then
                        print -u2 "$0: initialization aborted"
                        unfunction compinit compdef
                        unset _comp_dumpfile _comp_secure compprefuncs comppostfuncs _comps _patcomps _postpatcomps _compautos _lastcomp
                        return 1
                    fi
                    _i_wfiles=()
                    _i_wdirs=()
                else
                    (( $#_i_wfiles )) && _i_files=("${(@)_i_files:#(${(j:|:)_i_wfiles%.zwc})}")
                    (( $#_i_wdirs )) && _i_files=("${(@)_i_files:#(${(j:|:)_i_wdirs%.zwc})/*}")
                fi
            fi
            typeset -g _comp_secure=yes
        fi
    fi
    autoload -Uz compdump compinstall
    _i_done=''
    if [[ -f "$_comp_dumpfile" ]]
    then
        if [[ -n "$_i_check" ]]
        then
            IFS=$' \t' read -rA _i_line < "$_comp_dumpfile"
            if [[ _i_autodump -eq 1 && $_i_line[2] -eq $#_i_files && $ZSH_VERSION = $_i_line[4] ]]
            then
                builtin . "$_comp_dumpfile"
                _i_done=yes
            fi
        else
            builtin . "$_comp_dumpfile"
            _i_done=yes
        fi
    fi
    if [[ -z "$_i_done" ]]
    then
        typeset -A _i_test
        for _i_dir in $fpath
        do
            [[ $_i_dir = . ]] && continue
            (( $_i_wdirs[(I)$_i_dir] )) && continue
            for _i_file in $_i_dir/^([^_]*|*~|*.zwc)(N)
            do
                _i_name="${_i_file:t}"
                (( $+_i_test[$_i_name] + $_i_wfiles[(I)$_i_file] )) && continue
                _i_test[$_i_name]=yes
                IFS=$' \t' read -rA _i_line < $_i_file
                _i_tag=$_i_line[1]
                shift _i_line
                case $_i_tag in
                    (\#compdef) if [[ $_i_line[1] = -[pPkK](n|) ]]
                        then
                            compdef ${_i_line[1]}na "${_i_name}" "${(@)_i_line[2,-1]}"
                        else
                            compdef -na "${_i_name}" "${_i_line[@]}"
                        fi ;;
                    (\#autoload) autoload -Uz "$_i_line[@]" ${_i_name}
                        [[ "$_i_line" != \ # ]] && _compautos[${_i_name}]="$_i_line"  ;;
                esac
            done
        done
        if [[ $_i_autodump = 1 ]]
        then
            compdump
        fi
    fi
    for _i_line in complete-word delete-char-or-list expand-or-complete expand-or-complete-prefix list-choices menu-complete menu-expand-or-complete reverse-menu-complete
    do
        zle -C $_i_line .$_i_line _main_complete
    done
    zle -la menu-select && zle -C menu-select .menu-select _main_complete
    bindkey '^i' | IFS=$' \t' read -A _i_line
    if [[ ${_i_line[2]} = expand-or-complete ]] && zstyle -a ':completion:' completer _i_line && (( ${_i_line[(i)_expand]} <= ${#_i_line} ))
    then
        bindkey '^i' complete-word
    fi
    unfunction compinit compaudit
    autoload -Uz compinit compaudit
    return 0
}
compinstall () {
    # undefined
    builtin autoload -XUz
}
down-line-or-beginning-search () {
    # undefined
    builtin autoload -XU
}
edit-command-line () {
    # undefined
    builtin autoload -XU
}
is-at-least () {
    emulate -L zsh
    local IFS=".-" min_cnt=0 ver_cnt=0 part min_ver version order
    min_ver=(${=1})
    version=(${=2:-$ZSH_VERSION} 0)
    while (( $min_cnt <= ${#min_ver} ))
    do
        while [[ "$part" != <-> ]]
        do
            (( ++ver_cnt > ${#version} )) && return 0
            if [[ ${version[ver_cnt]} = *[0-9][^0-9]* ]]
            then
                order=(${version[ver_cnt]} ${min_ver[ver_cnt]})
                if [[ ${version[ver_cnt]} = <->* ]]
                then
                    [[ $order != ${${(On)order}} ]] && return 1
                else
                    [[ $order != ${${(O)order}} ]] && return 1
                fi
                [[ $order[1] != $order[2] ]] && return 0
            fi
            part=${version[ver_cnt]##*[^0-9]}
        done
        while true
        do
            (( ++min_cnt > ${#min_ver} )) && return 0
            [[ ${min_ver[min_cnt]} = <-> ]] && break
        done
        (( part > min_ver[min_cnt] )) && return 0
        (( part < min_ver[min_cnt] )) && return 1
        part=''
    done
}
up-line-or-beginning-search () {
    # undefined
    builtin autoload -XU
}
url-quote-magic () {
    # undefined
    builtin autoload -XUz
}

root@host# echo $SHELL
zsh

root@host#

你知道为什么会发生这种情况吗?我知道这sudo -s会覆盖所有环境变量,但我认为这不是一个问题。

环境变量:

root@host# echo $SHELL
zhs

root@host# dscl . -read $HOME UserShell
UserShell: /bin/zsh

对于普通用户来说也一样。

答案1

主要问题似乎是与您的用户具有不同的 zsh 配置。assudo -s使用目标用户的配置() 而不是调用用户,您会得到不同的 zsh 配置。

输出看起来像是来自functions内置函数(或typeset -fdeclare -f,它们是等效的),它似乎在以下函数中被调用:根的配置脚本:

/root/.zshrc
/root/.zshenv
/root/.zprofile
/root/.zlogin

如果你只想给予与您的普通用户相同的 zsh 配置,您可以直接复制它:

  1. 登录身份例如sudo -s
  2. 移走所有 zsh 配置文件可能有

    mkdir ~/zsh-old-conf
    mv ~/.zshrc ~/.zshenv ~/.zprofile ~/.zlogin ~/.oh-my-zsh ~/zsh-old-conf
    
  3. 将您的常规用户配置复制到根的家:

    cp -r /Users/REGULAR/.zshrc /Users/REGULAR/.oh-my-zsh ~/
    
  4. 检查配置现在是否有效。为了安全起见,请保持当前会话打开并从其他终端以 root 身份登录。这样,如果配置由于某种原因无法正常工作,您可以恢复更改。

相关内容