工欲善其事,必先利其器。通过屡次的重复配置 ubuntu 开发坏境,我终于决定花点时间总结一下,并将其写成一个自动化配置脚本。服务器实例:ubuntu 16.04,技术栈:shell,python。python
能够经过 hostname newname
修改主机名,不过最好是写入 /etc/hostname 文件,重启生效。为了让同一内网段的主机能够经过主机名访问,应在 /etc/hosts 中添加私有ip的解析。git
与命令提示符相关的环境变量是 PS1,初始值为:PS1='\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\u@\h:\w\$'
,各字符解释以下:github
#\u:当前登录用户名 #\h:当前主机名(如 ubuntu) #\H:当前主机的域名全称(ubuntu.ubuntu.com) #\w:当前目录(绝对路径) #\W:当前目录的 basename(只显示最后一级路径) #\$:通常用户为$,root 用户为# #\t:当前时间(24小时制,HH:MM:SS) #\T:当前时间(12小时) #\@:当前时间(Am/PM) #\d:当前日期 #\v:Bash 版本 #\V:Bash 的发布版本号 #\S:Shell 名称
对于我来讲我只须要 \u、\h、\W(\w 若是多进几个目录敲命令的体验就不好了),为了让命令行一目了然,最好给命令提示符加个颜色 PS1='${debian_chroot:+($debian_chroot)}\[\e[1;32m\]\u@\h\[\e[0m\]:\[\e[1;34m\]\W\[\e[0m\]\$ '
,颜色代码解释以下:shell
前景色 | 背景色 | 效果 |
---|---|---|
30m | 40; | 黑 |
31m | 41; | 红 |
32m | 42; | 绿 |
33m | 43; | 黄 |
34m | 44; | 蓝 |
35m | 45; | 紫 |
36m | 46; | 天蓝 |
37m | 47; | 白 |
#\033[背景;字体颜色m或者\e[背景;字体颜色m #0 从新设置属性到缺省设置 #1 设置粗体 #2 设置一半亮度(模拟彩色显示器的颜色) #4 设置下划线(模拟彩色显示器的颜色) #5 设置闪烁 #7 设置反向图象 #22 设置通常密度 #24 关闭下划线 #25 关闭闪烁 #27 关闭反向图象
Readline 的解释:从终端获取用户输入的字符流,辩认其中一些特定的字符序列,而后执行这些序列对应的函数或者宏。通俗一点讲就是绑定热键,好比在 bash 中默认按下 ctrl+a
执行的是光标回到行首的命令。ubuntu
此处我须要优化的是:一、Tab
补全时忽略大小写;二、经过 ↑↓
查询已输入关键字的历史记录。vim
vim ~/.inputrc "\e[A": history-search-backward "\e[B": history-search-forward # auto complete ignoring case set show-all-if-ambiguous on set completion-ignore-case on source ~/.inputrc
我须要:一、忽略重复的历史命令;二、保存更多的历史记录;三、忽略特定的历史记录;四、新建的终端同步 history。centos
export HISTCONTROL=ignoreboth # ignoreboth=ignoredups:ignorespace export HISTSIZE=10000 export HISTFILESIZE=20000 export HISTIGNORE='pwd:ls' # make sure all terminals save history shopt -s histappend export PROMPT_COMMAND="history -a; $PROMPT_COMMAND"
想要流畅地使用 git,我认为有几点必须配置:bash
安装完 git 以后,在 /etc/bash_completion.d
目录中会生成一个 git-prompt
文件:服务器
if [[ -e /usr/lib/git-core/git-sh-prompt ]]; then . /usr/lib/git-core/git-sh-prompt fi
打开/usr/lib/git-core/git-sh-prompt
,注释里面写了完整的操做步骤:app
# To enable: # # 1) Copy this file to somewhere (e.g. ~/.git-prompt.sh). # 2) Add the following line to your .bashrc/.zshrc: # source ~/.git-prompt.sh # 3a) Change your PS1 to call __git_ps1 as # command-substitution: # Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ' # ZSH: setopt PROMPT_SUBST ; PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ ' # the optional argument will be used as format string. # 3b) Alternatively, for a slightly faster prompt, __git_ps1 can # be used for PROMPT_COMMAND in Bash or for precmd() in Zsh # with two parameters, <pre> and <post>, which are strings # you would put in $PS1 before and after the status string # generated by the git-prompt machinery. e.g. # Bash: PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "' # will show username, at-sign, host, colon, cwd, then # various status string, followed by dollar and SP, as # your prompt. # ZSH: precmd () { __git_ps1 "%n" ":%~$ " "|%s" } # will show username, pipe, then various status string, # followed by colon, cwd, dollar and SP, as your prompt. # Optionally, you can supply a third argument with a printf # format string to finetune the output of the branch status
cp /usr/lib/git-core/git-sh-prompt .git-prompt.sh source .git-prompt.sh export PS1='${debian_chroot:+($debian_chroot)}\[\e[1;32m\]\u@\h\[\e[0m\]:\[\e[1;34m\]\W$(__git_ps1 " (%s)")\[\e[0m\]\$ ' export PROMPT_COMMAND='__git_ps1 "\[\e[1;32m\]\u@\h\[\e[0m\]:\[\e[1;34m\]\W\[\e[0m\]" "\$ "'
接下来还需赋值几个 git 环境变量让提示符显示更多 git 状态:
export GIT_PS1_SHOWDIRTYSTATE=true export GIT_PS1_SHOWCOLORHINTS=true export GIT_PS1_SHOWUNTRACKEDFILES=true export GIT_PS1_SHOWUPSTREAM="auto" git config --global alias.lg "log --color --graph --pretty=format:'%C(yellow)%h%Creset%C(cyan)%C(bold)%C(red)%d%Creset %s %C(green)[%cn] %Creset%C(cyan)[%cd]%Creset' --date=format-local:'%m-%d %H:%M'"
显示效果:
我有两个 git 帐号,分别是 gitee 和 github,且分别拥有各自的 name、email 和 ssh-key,我须要:
生成密钥对:
# ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa | rsa1] [-N new_passphrase] [-C comment] [-f output_keyfile] ssh-keygen -t rsa -C "github@youclk.com" -f ~/.ssh/github/id_rsa -N "" ssh-keygen -t rsa -C "gitee@youclk.com" -f ~/.ssh/gitee/id_rsa -N ""
编辑~/.ssh/config
Host github.com HostName github.com User git IdentityFile ~/.ssh/github/id_rsa Host gitee.com HostName gitee.com User git IdentityFile ~/.ssh/gitee/id_rsa
联通测试:
为了保证各仓库可以以正确的用户信息提交版本,须要取消全局的用户设置(我不理解为何 global 中的用户信息要去覆盖各仓库的,反过来不是更好吗)。
git config --global --unset user.name git config --global --unset user.emal
实现自动切换能想到的方案有不少,我更倾向于去修改 .git-prompt.sh
,在 __git_ps1 ()
函数末尾处增长一段逻辑:
if [ -z `git config user.name` ] && [ -z `git config user.email` ]; then local git_remote=`git remote -v` if [[ $git_remote =~ "github" ]]; then `git config user.name "github" && git config user.email "github@youclk.com"` elif [[ $git_remote =~ "gitee" ]]; then `git config user.name "gitee" && git config user.email "gitee@youclk.com"` fi fi
顺带多提一下,git 默认忽略文件大小写,然而做为轻微的强迫症患者,我必定要和远程仓库保持彻底一致:git config --global core.ignorecase false
。
我可能会一次性建立n台云服务器组成一个个集群,每一个集群中有一个 leader 和 n 个 follower,follower 只是提供计算能力,它应该把本身全权交给 leader,那么在 leader 上必须可以访问全部的
follower。这时候统一密钥对管理就很是有必要了,只须要一个私钥就能够访问全部的服务器,其实上一节提到的 git 密钥对也能够一块儿管理。本节展开的话其实就是一些脚本实现,因此统一交给下一节概括。
如今我须要思考的是如何使用一行命令来自动完成以上全部的配置。因为配置中涉及到一些私钥等铭感信息,因此脚本必须放置于 git 私有库中,可是 ubuntu 初始化的时候并无安装 git,因此还须要一个公有库来放置初始脚本,职能是安装 git 和访问私有库。最终我须要实现执行如下一行代码就完成整个 ubuntu 环境的配置:
# bash -c "$(curl -fsSL https://gitee.com/youclk/auto-config-entry/raw/master/centos/startup.sh)" bash -c "$(curl -fsSL https://gitee.com/youclk/entry/raw/master/ubuntu/setting.sh)"
初始的入口脚本比较简单(安装 git,下载私有库并执行 python 脚本):
#!/bin/bash apt update # install git if [ -z `which git` ]; then apt install git if [ ! $? -eq 0 ]; then exit 0; fi fi # switch path to .auto_config if [ ! -d ~/.auto_config ]; then mkdir ~/.auto_config if [ ! $? -eq 0 ]; then exit 0; fi fi cd ~/.auto_config # clone tools project if [ ! -d "tools" ]; then git clone https://gitee.com/youclk/tools.git if [ ! $? -eq 0 ]; then exit 0; fi fi cd tools/ubuntu python3 setting.py rm -r ~/.auto_config
如下是 python 部分的结构:
代码比较简单,都是一些读写文件和结合系统命令的操做(步骤和说明都写在注释中了,再也不赘述)。
setting.py
:
import os import socket import subprocess import sys sys.path.append('../') from utility import host def edit_hostname(): """ edit /etc/hostname and /etc/hosts """ old_hostname = socket.gethostname() new_hostname = str.strip(input('please write a hostname:')) if new_hostname and old_hostname != new_hostname: subprocess.check_call(['hostname', new_hostname]) hostname_dir = '/etc/hostname' hosts_dir = '/etc/hosts' # write hostname with open(hostname_dir, 'w') as f: f.write(new_hostname + '\n') # read hosts with open(hosts_dir, 'r') as f: hosts_lines = f.readlines() # write hosts with open(hosts_dir, 'w') as f: local_ip = host.get_local_ip() n = 0 for i in range(0, len(hosts_lines)): if local_ip in hosts_lines[i]: hosts_lines[i] = hosts_lines[i].replace(old_hostname, new_hostname) n += 1 if not n: hosts_lines.append('\n' + local_ip + '\t' + new_hostname + '\n') f.writelines(hosts_lines) def copy_config_files(): """ configure git history readLine commandPrompt """ subprocess.check_call('cp -r bash_script/. ~/.', shell=True) with open('/root/.bashrc', 'r+') as f: bashrc = f.read() if '.bashrc_pro' not in bashrc: f.write('\nsource ~/.bashrc_pro.sh\n') def configure_ssh_key(): # copy ssk_key subprocess.check_call('cp -r ssh_key/. ~/.ssh/.', shell=True) # chmod subprocess.check_call('chmod 400 ~/.ssh/*/id_rsa', shell=True) # configure git config github_config = ''' Host github.com HostName github.com User git IdentityFile ~/.ssh/git/id_rsa ''' gitee_config = ''' Host gitee.com HostName gitee.com User git IdentityFile ~/.ssh/git/id_rsa ''' if os.path.exists('/root/.ssh/config'): with open('/root/.ssh/config', 'r+') as f: git_config = f.read() if 'github.com' not in git_config: f.write(github_config) elif 'gitee.com' not in git_config: f.write(gitee_config) else: with open('/root/.ssh/config', 'w') as f: f.write(github_config + gitee_config) if __name__ == '__main__': if os.getuid() == 0: edit_hostname() copy_config_files() configure_ssh_key() print('success') else: print('please switch user => root')
host.py
(一些能够公用的函数单独抽离出来):
import socket def get_local_ip(): with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as net: net.connect(('8.8.8.8', 80)) return net.getsockname()[0]
.bashrc_pro.sh
:
#!/bin/bash # config git source .git_prompt.sh export PS1='${debian_chroot:+($debian_chroot)}\[\e[1;32m\]\u@\h\[\e[0m\]:\[\e[1;34m\]\W$(__git_ps1 " (%s)")\[\e[0m\]\$ ' if [ "$(whoami)" == "root" ]; then ps1_symbol="#" else ps1_symbol="$" fi export PROMPT_COMMAND='__git_ps1 "\[\e[1;32m\]\u@\h\[\e[0m\]:\[\e[1;34m\]\W\[\e[0m\]" "$ps1_symbol "' export GIT_PS1_SHOWDIRTYSTATE=true export GIT_PS1_SHOWCOLORHINTS=true export GIT_PS1_SHOWUNTRACKEDFILES=true export GIT_PS1_SHOWUPSTREAM="auto" # history export HISTCONTROL=ignoreboth # ignoreboth=ignoredups:ignorespace export HISTSIZE=10000 export HISTFILESIZE=20000 export HISTIGNORE='pwd:ls' shopt -s histappend export PROMPT_COMMAND="history -a; $PROMPT_COMMAND" # make sure all terminals save history # alias alias aliyun="ssh -i ~/.ssh/aliyun/id_rsa"
终于剔除了一块疙瘩,之后一拿到服务器就能够愉快地玩耍了。固然,以上脚本只适合我我的的使用习惯,部分代码逻辑比较粗暴,各位看官参考和多多点赞就好,切勿直接使用,如有更好的想法,欢迎留言。
个人公众号《有刻》,咱们共同成长!