我在 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 -f
或declare -f
,它们是等效的),它似乎在以下函数中被调用:根的配置脚本:
/root/.zshrc
/root/.zshenv
/root/.zprofile
/root/.zlogin
如果你只想给予根与您的普通用户相同的 zsh 配置,您可以直接复制它:
- 登录身份根例如
sudo -s
移走所有 zsh 配置文件根可能有
mkdir ~/zsh-old-conf mv ~/.zshrc ~/.zshenv ~/.zprofile ~/.zlogin ~/.oh-my-zsh ~/zsh-old-conf
将您的常规用户配置复制到根的家:
cp -r /Users/REGULAR/.zshrc /Users/REGULAR/.oh-my-zsh ~/
检查配置现在是否有效。为了安全起见,请保持当前会话打开并从其他终端以 root 身份登录。这样,如果配置由于某种原因无法正常工作,您可以恢复更改。