大家都知道 systemd 启个服务打 systemctl start nginx.service 实在是长的难受(尽管有Tab…), 于是 ArchWiki 上有介绍一个简单用 start nginx 来代替的方法, 但是这个方法没有 Bash 自动补全, 于是我自己折腾了一下..
补全函数都取自他们各自原来的 bash-completion 文件, 我只修改了一点点(可惜不能复用啊..).
嗯, 照例上代码…
/etc/bash.bashrc, 或者 ~/.bashrc 里添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
if ! systemd-notify --booted; then # not using systemd start() { sudo rc.d start $1 } restart() { sudo rc.d restart $1 } stop() { sudo rc.d stop $1 } else _target() { if [[ "$1" == *.service ]] then echo $1 else echo $1.service fi } export -f _target start() { sudo systemctl start $(_target $1) } export -f start restart() { sudo systemctl restart $(_target $1) } export -f restart stop() { sudo systemctl stop $(_target $1) } export -f stop enable() { sudo systemctl enable $(_target $1) } export -f enable status() { sudo systemctl status $(_target $1) } export -f status disable() { sudo systemctl disable $(_target $1) } export -f disable fi |
然后是自动完成:
/etc/bash_completion.d/systemctl_shortcut
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
# This file was part of systemd, modified 2012 by Felix Yan. # # Copyright 2010 Ran Benita # # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # systemd is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with systemd; If not, see <http://www.gnu.org/licenses/>. __systemctl() { systemctl --full --no-legend "$@" } __contains_word () { local word=$1; shift for w in $*; do [[ $w = $word ]] && return 0; done return 1 } __filter_units_by_property () { local property=$1 value=$2 ; shift 2 local units=("$@") local props IFS=$'\n' read -rd '' -a props < \ <(__systemctl show --property "$property" -- "${units[@]}") for ((i=0; $i < ${#units[*]}; i++)); do if [[ "${props[i]}" = "$property=$value" ]]; then printf "%s\n" "${units[i]}" fi done } __get_all_units () { __systemctl list-units --all \ | { while read -r a b; do printf "%s\n" "$a"; done; }; } __get_active_units () { __systemctl list-units \ | { while read -r a b; do printf "%s\n" "$a"; done; }; } __get_inactive_units () { __systemctl list-units --all \ | { while read -r a b c d; do [[ $c == "inactive" ]] && printf "%s\n" "$a"; done; }; } __get_failed_units () { __systemctl list-units \ | { while read -r a b c d; do [[ $c == "failed" ]] && printf "%s\n" "$a"; done; }; } __get_enabled_units () { __systemctl list-unit-files \ | { while read -r a b c ; do [[ $b == "enabled" ]] && printf "%s\n" "$a"; done; }; } __get_disabled_units () { __systemctl list-unit-files \ | { while read -r a b c ; do [[ $b == "disabled" ]] && printf "%s\n" "$a"; done; }; } __get_masked_units () { __systemctl list-unit-files \ | { while read -r a b c ; do [[ $b == "masked" ]] && printf "%s\n" "$a"; done; }; } _systemctl () { local cur=${COMP_WORDS[COMP_CWORD]} local prev=$1 local verb comps local -A OPTS=( [STANDALONE]='--all -a --defaults --fail --ignore-dependencies --failed --force -f --full --global --help -h --no-ask-password --no-block --no-legend --no-pager --no-reload --no-wall --order --require --quiet -q --privileged -P --system --user --version --runtime' [ARG]='--host -H --kill-mode --kill-who --property -p --signal -s --type -t --root' ) if __contains_word "$prev" ${OPTS[ARG]}; then case $prev in --signal|-s) comps=$(compgen -A signal) ;; --type|-t) comps='automount device mount path service snapshot socket swap target timer' ;; --kill-who) comps='all control main' ;; --kill-mode) comps='control-group process' ;; --root) comps=$(compgen -A directory -- "$cur" ) compopt -o filenames ;; --host|-H) comps=$(compgen -A hostname) ;; --property|-p) comps='' ;; esac COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) return 0 fi if [[ "$cur" = -* ]]; then COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") ) return 0 fi local -A VERBS=( [ALL_UNITS]='is-active is-enabled status show mask preset' [ENABLED_UNITS]='disable reenable' [DISABLED_UNITS]='enable' [FAILED_UNITS]='reset-failed' [STARTABLE_UNITS]='start' [STOPPABLE_UNITS]='stop condstop kill try-restart condrestart' [ISOLATABLE_UNITS]='isolate' [RELOADABLE_UNITS]='reload condreload reload-or-try-restart force-reload' [RESTARTABLE_UNITS]='restart reload-or-restart' [MASKED_UNITS]='unmask' [JOBS]='cancel' [SNAPSHOTS]='delete' [ENVS]='set-environment unset-environment' [STANDALONE]='daemon-reexec daemon-reload default dot dump emergency exit halt kexec list-jobs list-units list-unit-files poweroff reboot rescue show-environment' [NAME]='snapshot load' [FILE]='link' ) for ((i=0; $i <= $COMP_CWORD; i++)); do if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]} && ! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG}]}; then verb=${COMP_WORDS[i]} break fi done if [[ -z $verb ]]; then comps="${VERBS[*]}" elif __contains_word "$verb" ${VERBS[ALL_UNITS]}; then comps=$( __get_all_units ) elif __contains_word "$verb" ${VERBS[ENABLED_UNITS]}; then comps=$( __get_enabled_units ) elif __contains_word "$verb" ${VERBS[DISABLED_UNITS]}; then comps=$( __get_disabled_units ) elif __contains_word "$verb" ${VERBS[STARTABLE_UNITS]}; then comps=$( __filter_units_by_property CanStart yes \ $( __get_inactive_units \ | while read -r line; do \ [[ "$line" =~ \.(device|snapshot)$ ]] || printf "%s\n" "$line"; \ done )) elif __contains_word "$verb" ${VERBS[RESTARTABLE_UNITS]}; then comps=$( __filter_units_by_property CanStart yes \ $( __get_all_units \ | while read -r line; do \ [[ "$line" =~ \.(device|snapshot|socket|timer)$ ]] || printf "%s\n" "$line"; \ done )) elif __contains_word "$verb" ${VERBS[STOPPABLE_UNITS]}; then comps=$( __filter_units_by_property CanStop yes \ $( __get_active_units ) ) elif __contains_word "$verb" ${VERBS[RELOADABLE_UNITS]}; then comps=$( __filter_units_by_property CanReload yes \ $( __get_active_units ) ) elif __contains_word "$verb" ${VERBS[ISOLATABLE_UNITS]}; then comps=$( __filter_units_by_property AllowIsolate yes \ $( __get_all_units ) ) elif __contains_word "$verb" ${VERBS[FAILED_UNITS]}; then comps=$( __get_failed_units ) elif __contains_word "$verb" ${VERBS[MASKED_UNITS]}; then comps=$( __get_masked_units ) elif __contains_word "$verb" ${VERBS[STANDALONE]} ${VERBS[NAME]}; then comps='' elif __contains_word "$verb" ${VERBS[JOBS]}; then comps=$( __systemctl list-jobs | { while read -r a b; do printf "%s\n" "$a"; done; } ) elif __contains_word "$verb" ${VERBS[SNAPSHOTS]}; then comps=$( __systemctl list-units --type snapshot --full --all \ | { while read -r a b; do printf "%s\n" "$a"; done; } ) elif __contains_word "$verb" ${VERBS[ENVS]}; then comps=$( __systemctl show-environment \ | while read -r line; do printf "%s\n" "${line%%=*}=";done ) compopt -o nospace elif __contains_word "$verb" ${VERBS[FILE]}; then comps=$( compgen -A file -- "$cur" ) compopt -o filenames fi COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) return 0 } _systemctl_start () { _systemctl start } _systemctl_restart () { _systemctl restart } _systemctl_stop () { _systemctl stop } _systemctl_enable () { _systemctl enable } _systemctl_disable () { _systemctl disable } _systemctl_status () { _systemctl status } _rc_d () { local action cur prev actions='help list start stop reload restart' options='-s --started -S --stopped -a --auto -A --noauto' cur=${COMP_WORDS[COMP_CWORD]} arg=$1 if [[ -z "$arg" ]]; then COMPREPLY=($(compgen -W "${actions} ${options}" -- "$cur")) elif [[ "$arg" == help ]]; then COMPREPLY=() elif [[ "$arg" == start ]]; then COMPREPLY=($(comm -23 <(cd /etc/rc.d && compgen -f -X 'functions*' "$cur"|sort) <(cd /run/daemons/ && compgen -f "$cur"|sort))) elif [[ "$arg" =~ stop|restart|reload ]]; then COMPREPLY=($(cd /run/daemons/ && compgen -f "$cur"|sort)) else COMPREPLY=($(compgen -W "${options} $(cd /etc/rc.d && compgen -f -X 'functions*')" -- "$cur")) fi } _rc_d_start () { _rc_d start } _rc_d_restart () { _rc_d restart } _rc_d_stop () { _rc_d stop } if ! systemd-notify --booted; then complete -F _rc_d_start start complete -F _rc_d_restart restart complete -F _rc_d_stop stop else complete -F _systemctl_start start complete -F _systemctl_restart restart complete -F _systemctl_stop stop complete -F _systemctl_enable enable complete -F _systemctl_disable disable complete -F _systemctl_status status fi |
这个自动补全好复杂…
bash_completion.d 看起来没有必要的复杂,真不知道当初为什么选择用这种方式配置自动补全。
用 Oh-My-Zsh 的 systemctl 插件就一勞永逸搞定。
想让.bashrc好看点,就这么压缩了一下…
<pre>不好用嘛…诶…
俺把他编辑了下, 只有博主可以用代码的说- -|||
此外国旗确实不认ipv6
我来沙发的,因为看了后白看。
围观ZWW巨巨…