CentOS6.6 系统自带的 Python 版本是 Python2.6,但项目需要 Python2.7。

升级 Python2.6 到 Python2.7

  • 下载 Python源码包
    curl https://www.python.org/ftp/python/2.7.13/Python-2.7.13.tgz > Python-2.7.13.tgz
    tar -zxvf Python-2.7.13.tgz -C /opt/
    
  • 安装 Python
    cd /opt/Python-2.7.13
    ./configure
    make &&  make install
    

    默认安装在 /usr/loca/python2.7 目录下,也可以通过参数配置来指定安装路径 ./configure --prefix=/path/to/install/python
    安装完之后,系统默认的 Python 版本还是 Python2.6 的,需要修改:

    rm -f /usr/bin/python
    ln -s /usr/local/bin/python /usr/bin/python
    

    修改完之后,发现 yum 工具用不了了,因为 yum 工具是基于 Python2.6 的。将 /usr/bin/yum 的头部 #!/usr/bin/python 改为 #!/usr/bin/python2.6

安装 pip

cd /opt/
curl https://bootstrap.pypa.io/get-pip.py > get-pip.py
python get-pip.py
  • 如果出现错误:

    zipimport.ZipImportError: can’t decompress data; zlib not available

    是因为系统缺少了 zlibzlib-devel 库。

    yum install -y zlib zlib-devel
    

    安装成功之后,需要重新编译 Python:

    cd /opt/Python-2.7.13/
    make clean && make && make install
    # 重新编译完成之后再试一次安装 pip
    python get-pip.py
    
  • 如果接着出现错误:

    Could not fetch URL https://pypi.python.org/simple/pip/: There was a problem confirming the ssl certificate: Can’t connect to HTTPS URL because the SSL module is not available. – skipping

    是因为系统缺少 openssl-devel

    yum install -y openssl-devel
    

    安装成功之后,需要重新编译 Python:

    cd /opt/Python-2.7.13/
    make clean && make && make install
    # 重新编译完成之后再试一次安装 pip
    python get-pip.py
    

    到这里,我就成功安装了 pip。


总结 update.sh

#!/bin/sh

set -e
# 先安装需要的库:
yum install -y gcc zlib zlib-devel openssl-devel
# 下载 Python2.7 的源包
curl https://www.python.org/ftp/python/2.7.13/Python-2.7.13.tgz > Python-2.7.13.tgz
tar -zxvf Python-2.7.13.tgz -C /opt/
# 安装 Python
cd /opt/Python-2.7.13
./configure
make &&  make install
# 修改系统默认的 Python 版本
rm -f /usr/bin/python
ln -s /usr/local/bin/python /usr/bin/python
# 将 `/usr/bin/yum` 的头部 `#!/usr/bin/python` 改为 `#!/usr/bin/python2.6`
sed -i '1c #!/usr/bin/python2.6' /usr/bin/yum
# 接着安装 pip
cd /opt/
curl https://bootstrap.pypa.io/get-pip.py > get-pip.py
python get-pip.py

#!/bin/sh

### BEGIN INIT INFO
# Provides:          autossh-proxy
# Required-Start:    $network
# Required-Stop:     $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: start and stop autossh-proxy
# Description:       autossh-proxy is a manager of socket5 proxy by ssh
### END INIT INFO

# Author: lizs <lizsmail.com>

PATH=/sbin:/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

NAME=autossh
AUTOSSH=/usr/bin/autossh
AUTOSSH_PIDFILE=/var/run/$NAME.pid
# AUTOSSH_LOGFILE=/var/log/$BASE.log
# autossh can use environment variables to control features, e.g. AUTOSSH_PID.
# more info see `man autossh`
AUTOSSH_PID="/usr/bin/env AUTOSSH_PIDFILE=${AUTOSSH_PIDFILE}"
# The autossh args
AUTOSSH_ARGS="-M 0 -fqTN -D 1080 root@alizs.cc"

# Get lsb functions
. /lib/lsb/init-functions

do_start()
{
    start-stop-daemon --start --quiet --oknodo \
        --pidfile $AUTOSSH_PIDFILE \
        --make-pidfile \
        --exec $AUTOSSH_PID $AUTOSSH \
        -- $AUTOSSH_ARGS
    RETVAL="$?"
    return "${RETVAL}"
}

do_stop()
{
    # Return
    # 0 if the daemon has been stopped
    # 2 if the daemon could not be stopped
    # other if a failure occured
    start-stop-daemon --stop --quiet --oknodo \
        --retry=TERM/5/KILL/5 \
        --pidfile $AUTOSSH_PIDFILE \
        --remove-pidfile
    RETVAL="$?"
    return "${RETVAL}"
}

do_restart()
{
    exit 0
}


case "$1" in
    status)
        if init_is_upstart; then
            exit 1
        fi
        status_of_proc -p "${AUTOSSH_PIDFILE}" "${AUTOSSH}" "${NAME}"
        ;;
    start)
        if init_is_upstart; then
            exit 1
        fi
        log_begin_msg "Starting ${NAME}..."
        do_start
        log_end_msg "$?" # e.g. [ok], failed!, (warning)
        ;;
    stop)
        if init_is_upstart; then
            exit 1
        fi
        log_begin_msg "Stopping ${NAME}..."
        do_stop
        log_end_msg "$?"
        ;;
    restart)
        if init_is_upstart; then
            exit 1
        fi
        log_begin_msg "Restarting ${NAME}"
        do_restart
        log_end_msg "$?"
        ;;
    force-reload)
        exit 0
        ;;
    *)
        log_failure_msg "Usage: service ${NAME} {status|start|stop|restart}"
        ;;
esac

wiki: LSBInitScripts
Linux Standard Base Core Specification 3.1

#!/bin/sh

### BEGIN INIT INFO
# Provides:          autossh-proxy
# Required-Start:    $network
# Required-Stop:     $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: start and stop autossh-proxy
# Description:       autossh-proxy is a manager of socket5 proxy by ssh
### END INIT INFO

# Author: lizs <lizsmail.com>

PATH=/sbin:/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

NAME=autossh
AUTOSSH=/usr/bin/autossh
AUTOSSH_PIDFILE=/var/run/$NAME.pid
# AUTOSSH_LOGFILE=/var/log/$BASE.log
# autossh can use environment variables to control features, e.g. AUTOSSH_PID.
# more info see `man autossh`
AUTOSSH_PID="/usr/bin/env AUTOSSH_PIDFILE=${AUTOSSH_PIDFILE}"
# The autossh args
AUTOSSH_ARGS="-M 0 -fqTN -D 1080 root@alizs.cc"

# Get lsb functions
. /lib/lsb/init-functions

do_start()
{
    start-stop-daemon --start --quiet --oknodo \
        --pidfile $AUTOSSH_PIDFILE \
        --make-pidfile \
        --exec $AUTOSSH_PID $AUTOSSH \
        -- $AUTOSSH_ARGS
    RETVAL="$?"
    return "${RETVAL}"
}

do_stop()
{
    # Return
    # 0 if the daemon has been stopped
    # 2 if the daemon could not be stopped
    # other if a failure occured
    start-stop-daemon --stop --quiet --oknodo \
        --retry=TERM/5/KILL/5 \
        --pidfile $AUTOSSH_PIDFILE \
        --remove-pidfile
    RETVAL="$?"
    return "${RETVAL}"
}

do_restart()
{
    exit 0
}


case "$1" in
    status)
        if init_is_upstart; then
            exit 1
        fi
        status_of_proc -p "${AUTOSSH_PIDFILE}" "${AUTOSSH}" "${NAME}"
        ;;
    start)
        if init_is_upstart; then
            exit 1
        fi
        log_begin_msg "Starting ${NAME}..."
        do_start
        log_end_msg "$?" # e.g. [ok], failed!, (warning)
        ;;
    stop)
        if init_is_upstart; then
            exit 1
        fi
        log_begin_msg "Stopping ${NAME}..."
        do_stop
        log_end_msg "$?"
        ;;
    restart)
        if init_is_upstart; then
            exit 1
        fi
        log_begin_msg "Restarting ${NAME}"
        do_restart
        log_end_msg "$?"
        ;;
    force-reload)
        exit 0
        ;;
    *)
        log_failure_msg "Usage: service ${NAME} {status|start|stop|restart}"
        ;;
esac

Comment Conventions for Init Scripts

Reference: Comment Conventions for Init Scripts

### BEGIN INIT INFO
# Provides:          scriptname
# Required-Start:    $network
# Required-Stop:     $network
# Should-Start:      cgroup-lite
# Should-Stop:       cgroup-lite
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: short_description
# Description:       multiline_description
### END INIT INFO
  • 以上注释必须在以下两行分隔符内
    ### BEGIN INIT INFO
    ### END INIT INFO
    
  • 前后两行分隔符内的注释要以 # 开头,并且后面至少要跟着一个空格。(Description 除外,Description注释可以是多行描述。)
    # {keyword}: arg1 [arg2 ...]
    
    • Provides: boot_facility_1 [boot_facility_2 ...]
      Boot facilities provided by this init script. 该脚本要启动的服务的名称。
    • Required-Start: boot_facility_1 [boot_facility_2 ...]
      Facilities which must be available during startup of this service. The init-script system should insure init scripts which provide the Required-Start facilities are started before starting this script. 启动该脚本服务的依赖设备。
    • Required-Stop: boot_facility_1 [boot_facility_2 ...]
      Facilities which must be available during the shutdown of this service. The init-script system should avoid stopping init scripts which provide the Required-Stop facilities until this script is stopped. 关闭该脚本服务的依赖设备。
    • Should-Start: boot_facility_1 [boot_facility_2 ...]
      Facilities which, if present, should be available during startup of this service. This allows for weak dependencies which do not cause the service to fail if a facility is not available. 启动该脚本服务应该提供的依赖,如果没有,也不会造成启动服务失败。
    • Should-Stop: boot_facility_1 [boot_facility_2]
      Facilities which should be available during shutdown of this service. 关闭该脚本服务应该提供的依赖。
    • Default-Start: run_level_1 [run_level_2 ...]
    • Default-Stop: run_level_1 [run_level_2 ...]
      which run levels should by default run the init script with a start (stop) argument to start (stop) the services controlled by the init script. 该脚本服务的运行等级(0~6)。
      Run Level:

      • 0: halt
      • 1: single user mode.
      • 2: multiuser with no network services exported.
      • 3: normal/full multiuser.
      • 4: reserved for local user, default is normal/full multiuser
      • 5: multiuser with a display manager or equivalent
      • 6: reboot
    • Short-Description: short_description
      Provide a brief description of the actions of the init script. Limited to a single line of text. 脚本服务简述,只能够为一行。
    • Description: multiline_description
      Provide a more complete description of the actions of the init script. May span mulitple lines. In a multiline description, each continuation line shall begin with a # followed by tab character or a # followed by at least two space characters. The multiline description is terminated by the first line that does not match this criteria. 脚本服务的详细描述,可以分为多行。多行描述的时候,第二行开始每一行必须要 # 开头接着一个 tab 或者至少两个空格。
  • Facility Names
    Boot facilities are used to indicate dependencies in initialization scripts, as defined in Comment Conventions for Init Scripts. Facility names are assigned to scripts by the Provides: keyword. Facility names that begin with a dollar sign ($) are reserved system facility names.

    Note: Facility names are only recognized in the context of the init script comment block and are not available in the body of the init script. In particular, the use of the leading $ character does not imply system facility names are subject to shell variable expansion, since they appear inside comments.

    • $local_fs: all local file systems are mounted.
    • $remote_fs: all remote file systems are available. In some configurations, file systems such as /usr may be remote. Many applications that require $local_fs will probably also require $remote_fs.
    • $network: basic networking is available. Example: a server program could listen on a socket.
    • $named: IP name-to-address translation, using the interfaces described in this specification, are available to the level the system normally provides them. Example: if a DNS query daemon normally provides this facility, then that daemon has been started.
    • $portmap: daemons providing SunRPC/ONCRPC portmapping service as defined in RFC 1833: Binding Protocols for ONC RPC Version 2 (if present) are running.
    • $syslog: system logger is operational.
    • $time: the system time has been set, for example by using a network-based time program such as ntp or rdate, or via the hardware Real Time Clock.

The comment conventions described are only required for init scripts installed by conforming applications. Conforming runtime implementations are not required to use this scheme in their system provided init scripts.

Init Script Functions

Reference: Init Script Functions

. /lib/lsb/init-functions

Each conforming init script shall execute the commands in the file /lib/lsb/init-functions in the current environment (see shell special built-in command dot).

  • init_is_upstart: If the currently running init daemon is upstart, return zero; if the calling init script belongs to package which also provides a native upstart job, it should generally exit non-zero in this case.
  • status_of_proc: Return LSB status.
    • $1: daemon,init script 启动的进程
    • $2: 进程名称
    • -p: optional, daemon 的 pid 文件
     status_of_proc -p "/var/run/nginx.pid" "/usr/bin/nginx" "nginx"
    
  • log_begin_msg: 记录并打印信息,一般用在执行某个操作的开始位置,记录信息可以在 /var/log/syslog 查看,int log_begin_msg (char *message),传入值是一个信息字符串.
    log_begin_msg  "Starting autossh..."
    
  • log_end_msg: int log_end_msg (int exitstatus),传入值是一个整型的退出状态值,根据状态值返回:[ok], failed!, (warning) 等等。
    start-stop-daemon --start ...
    log_end_msg "$?"
    
  • log_success_msg, log_failure_msg, log_warning_msg
    更多函数说明可以查看 /lib/lsb/init-functions

Init Script Actions

Reference: Init Script Actions

Init scripts provided by conforming applications shall accept a single argument which selects the action:

  • start: Start the service
  • stop: Stop the service
  • restart: Stop and restart the service if the service if already running, otherwise start the service.
  • try-restart: Restart the service if the service is already running.
  • reload: Cause the configuration of the service to be reloaded without actually stoping and restarting the service.
  • force-reload: Cause the configuration to be reloaded if the service support this, otherwise restart the service if it is running.
  • status: Print the current status of the service.

The start, stop, restart, force-reload and status actions shall be supported by all init scripts; the reload and try-restart actions are optional. Other init-scripts actions may be defined by the init script.

case "$1" in
    status)
        exit 0
        ;;
    start)
        exit 0
        ;;
    stop)
        exit 0
        ;;
    restart)
        exit 0
        ;;
    force-reload)
        exit 0
        ;;
    *)
        log_failure_msg "Usage: service ${NAME} {status|start|stop|restart}"
        ;;
esac

Installation and removal of Init Scripts

Reference: Linux – 管理系统服务

  • CentOS
    Redhat 提供了 chkconfig 命令来管理系统的服务:

    • chkconfig --list:所有服务列表
    • chkconfig --list serviceName:只显示 serverName 服务
    • chkconfig serviceName on:开启 serverName 服务的自动启动
    • chkconfig serviceName off:关闭 serverName 服务的自动启动
    • chkconfig --add serviceName:添加服务
    • chkconfig --del serviceName:删除服务
  • Ubuntu
    Ubuntu 是没有 chkconfig 命令的,而是提供了另外的命令来实现管理服务:

    • sudo update-rc.d serviceName defaults:添加服务,默认添加服务为自动启动,即 /etc/rc0.d//etc/rc6.d 各级别里面都添加了服务的启动软链接。
    • sudo update-rc.d serviceName remove:删除服务,默认会删除所有级别的服务,即彻底删除服务。

      如果,你想要配置各级别的启动情况,可以删除相应级别目录里面的服务软链接。

    • systemctl daemon-reload:修改过服务之后,用该命令来重新加载服务。

场景

在一个内存只有 700M 左右的服务器上面使用 git push 一个带 submodule 的项目的时候,出错:


fatal: Out of memory, malloc failed (tried to allocate 79691777 bytes)

当停止一些占用内存的服务之后,发现又可以正常 push。Stackoverflow 之后,解决办法有:添加内存或添加 swap 空间。cat /proc/swaps 之后发现服务器没有设置 swap 空间。

swap 简介

计算机的内存分为物理内存和虚拟内存。物理内存,即实际内存大小(RAM);虚拟内存,是由磁盘虚拟出来的,在内存不够的时候可以起到一个代替物理内存的作用,也就是 swap。

当产生一个新进程的时候,机器会判断当前物理内存是否有空闲运行该进程,如果没有,则会根据优先级将物理内存中运行的一个或多个进程挂起,并将挂起的进程放到 swap 中等待,然后,把这个新进程放入物理内存中运行。等到物理内存中有进程结束释放空间之后,再将在 swap 中挂起等待的进程调到物理内存中运行。

当物理内存使用达到一个比例之后,机器就会使用 swap 作为临时内存使用。这个比例保存在 /proc/sys/vm/swappiness 中,大小从 0 到 100。0,表示最大限度使用内存。更改该比例的大小:


echo 60 > /proc/sys/vm/swappiness

当物理内存和 swap 内存都使用完的时候,就会出现 out of memory 之类的错误。

添加/开启/关闭 swap

创建一个 swap 文件


dd if=/dev/zero of=/root/swap1 bs=1M count=1024

执行完之后就会产生文件 /root/swap1

为了安全起见,设置一下文件的权限


chmod 600 /root/swap1

将文件变为 swap 文件


mkswap /root/swap1

开启 swap


swapon /root/swap1

该命令还可以有其它参数,如 -p 设定 swap 的优先级。

使 swap 开机生效

/etc/fstab 文件主要存放文件系统的静态信息。在文件中添加:


/root/swap1 none swap defaults 0 0

各个参数之间可以用空格或 tab 键隔开。

关闭 swap


swapoff /root/swap1

参考 unix/linux: 2 ways to add swap space

Expect, an extension to the Tcl (Tool Command Language) scripting language, and it is a scripting language to interface with programs such as FTP, telnet, fsck, ssh, and others that normally cannot be automated from a shell script.

使用情景

Expect 可以实现自动交互的功能,所以,很常用的一种情景就是为我们自动输入密码。如:ssh 登录,git push/pull 等情景。

安装

  • Ubuntu

sudo apt-get install expect
  • CentOS

sudo yum install expect

Expect 需要 Tcl 编程语言的支持,所以必须先安装 Tcl。

实例

Expect 脚本使用的是 Tcl 的语法

  • 批量更新 git 仓库的内容(git pull)

#!/usr/bin/expect set password "123456" foreach app { /root/app/ic/ic-server/ /root/app/ic/ic-client/ } { cd $app spawn git pull expect { "Username*" {send "lizs\r"} "*assword*" { send $password interact } } }

更多使用参考 Expect-wiki.

Linux Desktop Entry 文件以 .desktop 为后缀,保存了程序启动配置信息。类似 Windows 下的快捷方式。Desktop Entry 文件一般存放在 /usr/share/applications 目录下。

jetbrains-phpstorm.desktop


[Desktop Entry] Version=1.0 Type=Application Name=PhpStorm Icon=/opt/PhpStorm-2016.2/bin/webide.png Exec="/opt/PhpStorm-2016.2/bin/phpstorm.sh" %f Comment=Develop with pleasure! Categories=Development;IDE; Terminal=false StartupWMClass=jetbrains-phpstorm

配置参数

  • Version:可选,版本号

  • Type:必选,Desktop Entry 文件的类型。常见类型有 ApplicationLink

    • Application:表示当前 Desktop Entry 文件为一个应用程序

    • Link:表示当前 Desktop Entry 文件指向一个 URL

  • Encoding:可选,指定当前 Desktop Entry 文件中字符串的编码方式

  • Name:必选,应用程序名称。在 GUI 中看到的是该名称,而不是文件名称。如 jetbrains-phpstorm.desktop 看到是名称是 PhpStorm,而不是 jetbrains-phpstorm

  • Comment:可选,当前应用的描述

  • Exec:可选,只有在 Type=Application 时,才有意义。表示启动应用程序要执行的命令

  • URL:可选,只有在 Type=URL 时,才有意义。定义该 Desktop Entry 文件指向的 URL

  • Icon:可选,图标

  • Categories:可选,只有在 Type=Application时,才有意义。指定该应用程序在菜单中显示的类型

  • Terminal:可选,布尔值,指定该应用程序是否需要在 Terminal 中运行。

更多配置参数可以参考 Desktop Entry Specification

Linux 系统的服务脚本放在 /etc/init.d 目录下。所以,想要添加服务,首先需要编写可执行服务的脚本,然后放到该目录下。具体编写,可以参照 /etc/init.d/ 目录下面的已有服务。

CentOS

Redhat 提供了 chkconfig 命令来管理系统的服务:

  • chkconfig --list:所有服务列表

  • chkconfig --list serviceName:只显示 serverName 服务

  • chkconfig serviceName on:开启 serverName 服务的自动启动

  • chkconfig serviceName off:关闭 serverName 服务的自动启动

  • chkconfig --add serviceName:添加服务

  • chkconfig --del serviceName:删除服务

Ubuntu

Ubuntu 是没有 chkconfig 命令的,而是提供了另外的命令来实现管理服务:

  • sudo update-rc.d serviceName defaults:添加服务,默认添加服务为自动启动,即 /etc/rc0.d//etc/rc6.d 各级别里面都添加了服务的启动软链接。

  • sudo update-rc.d serviceName remove:删除服务,默认会删除所有级别的服务,即彻底删除服务。

如果,你想要配置各级别的启动情况,可以删除相应级别目录里面的服务软链接。

  • systemctl daemon-reload:修改过服务之后,用该命令来重新加载服务。

vim 配置文件: ~/.vimrc,在.vimrc文件中可以配置 vim 的永久属性。.vimrc 文件里面的注释用英文的双引号"。配置 vim 暂时属性可以在命令模式下设置,如给当前文件显示行号::set nu

  • 行号,暂时显示行号,:set nu;暂时取消行号,:set nonu。永久显示行号。终端输入命令 vim ~/.vimrc,打开文件后,添加 set nu

  • Tab 键占空格数,set tabstop=4


  • 保存,:w

  • 保存到新文件,:w new_file

  • 保存到已有文件,:w! exist_file


  • 退出,没有做过修改。:q

  • 退出,保存修改。:wq:x

  • 退出,放弃修改。:q!


  • 查找,从开头到结尾查找文件“word” /word;从结尾到开头查找“word” ?word。查看下一个,按n

  • 替换

    在命令模式下,可以用 s 命令来替换字符串:: [option1]s/oldStr/newStr/[option2]

    • [option2] 可以是 g c p
      • g:表示全局替换

      • c:表示进行确认再替换

      • p:表示替换结果逐行显示(Ctrl + L 恢复屏幕)

    • : s/oldStr/newStr/:替换当前行第一个 oldStr 字符串

    • : s/oldStr/newStr/g:替换当前行所有 oldStr 字符串

    • : m, ns/oldStr/newStr:替换从第 m 行到第 n 行中的第一个 oldStr 字符串

    • : n, $s/oldStr/newStr/g:替换从第 n 行到最后一行的所有 oldStr 字符串

    • : ., $s/oldStr/newStr/:替换从当前行到最后一行的第一个 oldStr 字符串

    • : %s/oldStr/newStr/g:替换每一行中所有的 oldStr 字符串

    • : %s/oldStr/newStr/c:替换每行中的第一个 oldStr 字符串,但是替换需要确认

    • : %s/oldStr/newStr/gc:替换所有的 oldStr 字符串,但是替换需要确认

    • 可以使用 #+ 代替 / 作为分隔符,此时命令中出现的 / 将作为普通字符处理,如:

      • : s#oldStr/#newStr#:替换当前行的 oldStr/ 字符串

      • : %s+/oldStr/+newStr:替换所有 /oldStr/ 字符串


  • 跳到指定行

    • 正常模式下,nggnGn 为行号。如跳到 35 行,35ggG 可以直接跳到最后一行。

    • 命令模式下,:n

    • 如果想打开文件即跳转,sudo vim +n file_name


  • 复制一(n)行

    正常模式下,复制光标所在的整行,yy;复制 n 行(从光标所在行开始),nyy

    或者:

    命令模式下,复制从第 n 行到 n + 5 行的内容到第 m 行后面 n, n+5 copy/co m

    或者:

    正常模式下,把光标移到要开始复制的那一行 ngg,然后,计算一下删除哪几行(如,n ~ n+5,包括n和n+5),执行 d5(即删除第 n 到第 n+5 这 6 行)。删除完之后,恢复 u。将光标移到要粘贴的位置,p

  • 粘贴一行

    正常模式下,将复制到的内容粘贴到光标所在的行,p

  • 删除一行

    正常模式下,删除光标所在的行,dd

  • 删除多行

    正常模式下,删除光标所在的行开始的 n + 1 行,dnn的值为最后一行的行号减去开始行的行号


  • 撤消

    在正常模式下,撤消上一步,u

  • 恢复撤消

    在正常模式下,恢复撤消的内容,Ctrl + r


光标移动

  • h:向左;nh,向左移动 n 个字符。

  • j:向下;nj,向下移动 n 行。

  • k:向上;nk,向上移动 n 行。

  • l:向右。nl,向右移动 n 个字符。

  • w:向右移动到下个单词的首个字符处;nw,向右移动 n 个单词。

  • b:与 w 方向相反。

  • e:向右移动到下个单词的尾字符处;ne,向右移动 n 个单词。

  • ge:与 e 方向相反。

  • ^:光标移动到该行的第一个字符处(不包括空格)。

  • $:光标移动到该行的尾字符处。

  • 0:光标移动到该行的行首。

  • nggnG:光标移动到 n 行的第一个字符上。

  • gg:移动到文件首行。

  • G:光标移动到文件末行。

  • Ctrl + f:向上翻页。

  • Ctrl + b


  • 选择字符

    正常模式下,v,进入可视模式,然后通过光标移动来选择字符。


复制

  • y:复制选中的字符,选中字符可以在可视模式下,然后 hjkl 选择。

  • yw:复制当前光标位置到单词尾字符的内容到 vim 缓冲区。nyw,复制 n 个单词。

  • y^:复制当前光标位置到行首的内容到 vim 缓冲区。

  • y$:复制当前光标位置到行尾的内容到 vim 缓冲区。

  • yy:复制当前行的内容到 vim 缓冲区。nyy,复制 n 行。

  • 复制第 m 行到第 n 行的内容到 vim 缓冲区:

    命令模式下,m, ny

  • 复制第 m 行到第 n 行的内容到第 k 行后面:

    命令模式下,m, n copy/co k

以上复制,都是将内容复制到 vim 剪贴板,而且 vim 具有多个剪贴板,而我们平时操作的复制粘贴是将内容保存到系统的剪贴板。所以,当你想从另外的地方复制了一段内容(如,浏览器某个网址上复制一段内容)到当前 vim 来,是不能够直接用 p 来粘贴的。因为,p 命令是默认粘贴当前 vim 缓冲区的内容。

vim 中的剪贴板内容是保存在 register 中的,在 vim 命令模式下,可以用 reg 命令来查看 register 中的内容。

(ubuntu 15.10)我们可以看到,系统中复制的内容保存在 "*"+ 的 register 中。所以,如果我们想要将系统剪贴板的内容粘贴到当前 vim,只需在粘贴命令前添加 register 标记就可以了。

  • "*p"+p:将系统剪贴板的内容粘贴到光标后面。

  • "*y“+y:将当前 vim 中选中的内容复制到系统剪贴板中。


删除(非插入模式下)

  • xd:删除当前光标下的字符。

  • dw:删除光标之后的单词剩余部分。

  • d$:删除光标之后的该行剩余部分。

  • dd:删除当前行。

  • dnn为最后一行的行号减去开始行的行号的值,删除光标所在的行开始的 n + 1 行。

  • c:删除光标下的字符后,进入插入模式。

  • cc:删除当前行之后,进入插入模式。

  • :wq 强制性写入文件并退出(存盘并退出 write%quite)。即使文件没有被修改也强制写入,并更新文件 的修改时间。
  • :x 写入文件并退出。仅当文件被修改时才写入,并更新文件修改时间;否则不会更新文件修改时间。

这两者一般情况下没什么不一样,但是在编程方面,对编辑源文件可能会产生重要影响。因为文件即使没有修改,:wq 强制更新文件的修改时间,这样会让 Makefile 编译整个项目时以为文件被修改过了,然后就得重新编译链接生成可执行文件。这可能会产生让人误解的后果,当然也产生了不必要的系统资源花销。

Windows 系统安装软件用 *.exe 可执行文件。那么 Linux 系统安装软件是怎样的呢?


本地安装

本地安装,即下载软件的安装包到本地,然后根据软件包的类型进行安装。常见的软件包:

  • 源码包

软件的源代码安装包,如 tar、tar.gz、bz 等压缩包。源码包是软件的源程序,是没有经过编译的。所以,源码包不能够直接运行安装,要先将其解压后,编译成为可执行文件才能够安装。编译方法,一般在安装包的 README 文件里面都有详细的操作步奏。

  • rpm 包

rpm 后缀的安装包,是可执行文件安装包,可以用 rpm 命令进行安装。RPM,RedHat Package Manager。

  • deb 包

deb 后缀的安装包,debian 及其衍生版本的安装包(如 ubuntu),是可执行文件安装包。可以用 dpkg 命令进行安装。

本地软件包的安装,只是安装软件包本身的内容,是不可以自动处理安装包的依赖关系的!比如:你要安装 Django,就要先安装 Python。


在线安装

在线安装,即不用将软件包下载到本地,直接用命令就可以下载并安装软件到本地。所以,在线安装是会处理安装包的依赖关系的,即会同时安装依赖包。

在线安装软件,需要 Linux 系统有该软件的软件源。软件源,可以理解为软件的来源、仓库,你在线安装软件,其实就是从软件源的服务器上下载软件包,然后安装到你的机器上。

Ubuntu

软件源

/etc/apt/sources.list/etc/apt/sources.list.d/*.list 都是保存了 ubuntu 软件源信息的文件。用户手动添加的第三方软件源一般都是保存在 /etc/apt/sources.list.d 目录下相应的 list 后缀的文件中。

PPA 源

PPA(Personal Package Archives),即个人软件包档案。很多软件包由于各种原因,不能够进入 Ubuntu 官方的软件库。为了方便 Ubuntu 用户,launchpad.net 提供了 PPA,允许用户建立自己的软件仓库,自由上传软件。PPA 也被用来对一些打算进入 Ubuntu 官方仓库的软件或者某些软件的新版本进行测试。

有些 PPA 源是非官方的,使用 PPA 源尽量使用官方的 PPA。

添加软件的 PPA 源:

https://launchpad.net/ubuntu/+ppas搜索软件的 PPA 源,从搜索结果中可以看到相关信息中,然后添加:


sudo add-apt-repository ppa:xxx sudo apt-get update

以上命令添加完 ppa 源并且更新之后,实际上是在 /etc/apt/sources.list 或者 /etc/apt/sources.list.d/*.list 里面添加了该软件的源信息,如:


deb http://ppa.launchpad.net/wiznote-team/ppa/ubuntu wily main

所以,你也可以手动将以上软件源信息添加 /etc/apt/sources.list/etc/apt/sources.list.d/*.list 里面。

在线安装软件更新软件源的相关命令

Ubuntu 系统本地软件包(*.deb)用 dpkg 安装,在线包安装管理使用 apt-get

  • sudo apt-get install

Ubuntu 在线安装软件包命令,前提是你本地有该软件的源信息。不同于 Ubuntu 本地安装命令 dpkg,该命令是会处理软件包的依赖的。

  • sudo apt-get update

同步 *.list 文件中的源的索引,即更新软件源信息,如软件版本、依赖关系等。

  • sudo apt-get upgrade

与软件源中的软件信息进行对比,然后更新软件。所以,更新软件之前要先 update,同步软件源服务器中包的索引。

update 仅仅是更新软件包的版本,不会管软件包的依赖关系是否随着版本的更新发生了改变,而进行相应的添加或删除包。

  • sudo apt-get dist-upgrade

同样是更新软件,不过会针对软件包的依赖关系进行添加或删除依赖包。e.g. 软件包 A 原先是依赖 B、C 包的,但是 A 升级之后,只需要依赖 B 包就可以了。这时候,dist-upgrade 会将 C 包删除(假如,其它依赖 C 包的软件)。

CentOS

CentOS 系统本地软件包(*.rpm) 用 rpm 安装,在线安装软件用 yum

YUM(Yellow dog Updater, Modified)是一个在 Fedora 和 RedHat 以及 CentOS 中的 Shell 前端软件包管理器。基于 RPM 包管理,能够从指定的服务器自动下载 RPM 包并安装。同时,会自动处理安装包的依赖关系。所以,同样需要有相应的软件源。

软件源

/etc/yum.repos.d/*.repo 文件保存了 CentOS 系统的软件源信息。

  • CentOS-Base.repo:yum 网络源的配置文件。默认是国外的源,如果服务器在国内可以换相应版本的 163 源,安装更新会快很多。

  • CentOS-Media.repo:本地源的配置文件。

添加软件源

CentOS 默认自带 CentOS-Base.repo 源,但官方源中为了系统的稳定,包含的软件源的版本非常的少和版本都是比较稳定的旧版本。所以,我们想要安装的很多软件在官方源都是安装不了的。这时候,我们就要添加第三方软件源,下面是常见的几个有用的软件源:

  • EPEL 源

EPEL(Extra Packages for Enterprise Linux),企业版 Linux 附加软件包。EPEL 是由 Fedora 社区打造,为 RHEL 及衍生发行版(如 CentOS 等)提供高质量附加软件包项目。

EPEL 包含了两个源:

+    `epel.repo`:包含了 EPEL 源的 gpg 密钥和软件源信息。

+    `epel-testing.repo`:包含了最新的测试软件包,其软件版本很新但是有可能不是很稳定。

CentOS 7 添加 epel 源:


yum install epel-release
  • REMI 源

REMI 源提供了 CentOS 和 RHEL 的核心包的更新版本,尤其是 PHP/MySQL 系列。

CentOS 7 添加 remi 源:


yum localinstall http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
  • RPMForge 源

RPMForge 是 CentOS 系统下的软件仓库,拥有 4000 多种软件包,被 CentOS 社区认为是最安全稳定的一个软件仓库。

CentOS 7 添加 RPMForge 源:


yum localinstall --nogpgcheck http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el7.rf.x86_64.rpm
  • 手动添加软件源

你也可以手动添加软件源。比如,CentOS 7 添加 Nginx 软件源。先创建文件 /etc/yum.repos.d/nginx.repo,然后添加:



[nginx] name=nginx repo baseurl=http://nginx.org/packages/centos/7/$basearch/ gpgcheck=0 enabled=1

Both RPM packages and Debian/Ubuntu repositories use digital signatures to verify the integrity and origin of the downloaded package. In order to check a signature it is necessary to download nginx signing key and import it to the rpm or apt program’s keyring.

下载软件源签名:


sudo rpm --import nginx_signing.key

Nginx 官网有详细的介绍:Linux packages for stable version

管理软件源

添加了第三方源之后,各个软件仓库之间并不能够保证完全兼容。我们可以通过安装 yum-priorities 插件来管理各个源。

Yum Priorities 插件可以通过给各个源设定不同的优先级,来管理各个源,从而保证系统的稳定性。

  • 安装

yum install yum-priorities
  • 使用

在各个源文件 *.repo 中添加 priority=nn 为1 – 99 的整数,数值越小优先级越高。