一线运维必备技能知识串讲(一)

运维

从事运维工作多年,一直在一线进行救火工作。你是否还记得服务器出现问题CTO站在你身后时你疯狂输出的样子和心情。后续我会跟大家分享一线运维必备的一些基础命令,希望阅读之后大家可以把这些手法融入到你的血液里,让你遇到问题的时候各种命令都可以信手拈来。

控制台使用技巧

操作快捷键:

  • 使用ctrl+r寻找你使用过的命令,直接输入你想要的命令行。(请各位不要把常用命令复制到一个txt里面,想到哪个的时候过去复制一下,实在是看不下去了。)在这里我分享一个bash脚本供大家保存命令(安全问题自行考虑),请将该脚本放置到~/.bashrc,自行引用,引用完毕后输入h直接展示历史记录。(不兼容zsh,zsh用户慎用)
# history
# persistent shell history with advanced search
#
# Copyright (C) 2013 Mara Kim, Kris McGary
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program 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 General Public License along with
# this program. If not, see http://www.gnu.org/licenses/.


### USAGE ###
# Source this file in your shell's .*rc file


### SETTINGS ###

if [ -z "$ALL_HISTORY_FILE" ]
then
  ALL_HISTORY_FILE=~/.bash_all_history
fi

### END SETTINGS ###


#set up history logging of commands
export HISTTIMEFORMAT='    %F %T    '
export HISTCONTROL='ignorespace'
PROMPT_COMMAND="_log_history; ${PROMPT_COMMAND}"
_HISTNUM=""
_LAST_COMMAND=""
declare -a _PWD

# logging function
function _log_history {
local directory="$(pwd -P)"
local histnum="$(history 1 | sed 's/ *\([0-9]*\).*/\1/')"
if [ -z "$_HISTNUM" ]
then
 _HISTNUM="$histnum"
elif [ "$histnum" != "$_HISTNUM" ]
then
 if [ "$directory" != "$_PWD" ]
 then
  local match
  local i
  for i in {1..8}
  do if [ "$directory" = "${_PWD[$i]}" ]
     then unset _PWD[$i]
          match="true"
     fi
  done
  if [ -z "$match" ]
  then unset _PWD[9]
  fi
  _PWD=( "$directory" "${_PWD[@]}" )
  local directory="${_PWD[1]}"
 fi
 local command="$(cat <(history 1 | head -1 | sed 's/[^    ]*    //') <(history 1 | tail -n +2))"
 printf '%q\t%q\t%s\n\x00' "$USER@$HOSTNAME" "$directory" "$command" >> "$ALL_HISTORY_FILE"
 if [ "$_LAST_COMMAND" = "$command" ]
 then
  history -d "$histnum"
 else
  _HISTNUM="$histnum"
  _LAST_COMMAND="$command"
 fi
fi
}

# history
h () {
  gawk_history_interactive "/" 1 "$@"
}

# history of commands run in this directory and subdirectories (with grep)
dh () {
  gawk_history_interactive "$(printf '%b' "$(pwd -P)")" 1 "$@"
}

# history of commands run in this directory only (with grep)
ldh () {
  gawk_history_interactive "$(printf '%b' "$(pwd -P)")" 0 "$@"
}

# select from history
h! () {
  select_history "/" 1 "$@"
}

# select from history
dh! () {
  select_history "$(printf '%b' "$(pwd -P)")" 1 "$@"
}

# select from history
ldh! () {
  select_history "$(printf '%b' "$(pwd -P)")" 0 "$@"
}

# select from working directory history
cd! () {
  local histline
  local history
  local item
  local line

  if [ -z "$*" ]
  then history=( "${_PWD[@]}" )
  else while read -r -d '' histline
    do history+=( "$histline" )
    done < <( gawk_directory_history "/" 1 "$@" )
  fi

  select item in "${history[@]}"
  do
      if [ -z "$item" ]
      then break
      fi

      # Read user edited command
      read -er -i "$item" -p '$ ' item
      while bash -n <<<$item 2>&1 | grep 'unexpected end of file' > /dev/null || [ -z "${item%%*\\}" ]
      do
        read -r -p '> ' line
        item="$item"$'\n'"$line"
      done

      # Add command to history and run
      history -s "cd $item"
      cd "$item"
      return $?
  done
}

# bash completions

complete -cf h
complete -cf dh
complete -cf ldh
complete -cf h!
complete -cf dh!
complete -cf ldh!

# select history implementation
select_history () {
  local histline
  local history
  local item
  local line

  while \read -r -d '' histline
  do
      history+=( "$histline" )
  done < <( gawk_history "$@" |
            gawk 'BEGIN { RS="\0"; FS="\t"; }
            { for(i = 5; i <= NF; i++) $4 = $4 "\t" $i}
            { a[$4] = NR }
            END { PROCINFO["sorted_in"] = "@val_num_desc";
                  num = 0;
                  for (i in a) { printf "%s\0", i; num++; if (num == 10) break } }' )

  select item in "${history[@]}"
  do
      if [ -z "$item" ]
      then break
      fi

      # Read user edited command
      read -er -i "$item" -p '$ ' item
      while bash -n <<<$item 2>&1 | grep 'unexpected end of file' > /dev/null || [ -z "${item%%*\\}" ]
      do
        read -r -p '> ' line
        item="$item"$'\n'"$line"
      done

      # Add command to history and run
      history -s "$item"
      eval "$item"
      return $?
  done
}

# directory history implementation
gawk_directory_history () {
  gawk_history "$@" |
    gawk 'BEGIN { RS="\0"; FS="\t"; }
          { a[$2] = NR }
          END { PROCINFO["sorted_in"] = "@val_num_desc";
                num = 0;
                for (i in a) { printf "%s\0", i; num++; if (num == 10) break } }'
}

# interative gawk history implementation
gawk_history_interactive () {
    # read arguments
    local state="first"

    for arg in "$@"
    do
        if [ "$state" = "first" ]
        then
            state="second"
        elif [ "$state" = "second" ]
        then
            state=""
        elif [ "$arg" = "-h" -o "$arg" = "--help" ]
        then
            printf 'Usage: [[l]d]h[!] [CONTEXT] [TIMESPEC] [--] [SEARCH]
Search command history.

SEARCH is a regular expression understood by `gawk`
used to match the executed command.

TIMESPEC is an argument of the form "[START..END]",
where START and END are strings understood by `date`.
A single day may be specified by "[DATE]".

CONTEXT is an argument of the form "USER@HOST:DIRECTORY"
or "USER@HOST::DIRECTORY", where each field is optional.
"@" is used to specify user or host filters.
":" is used to specify a directory filter.
"::" may be used instead to exclude subdirectories.

Select from the 10 most recent matching entries
adding `!` to the command (ex. `h!`).
The selected command may be edited before execution.
'
            return 0
        fi
    done
    gawk_history "$@" | tr -d '\000' | less -FX +G
}

# core gawk history implementation
gawk_history () {
    # read arguments
    local state="first"
    local search
    local timespec
    local user
    local host
    local argdir
    local directory
    local recursive_dir

    for arg in "$@"
    do
        if [ "$state" = "first" ]
        then
            directory="$arg"
            state="second"
        elif [ "$state" = "second" ]
        then
            recursive_dir="$arg"
            state=""
        elif [ "$state" = "input" ]
        then
            search+="${arg}.*"
        elif [ "$state" = "time" ]
        then
            timespec="$timespec $arg"
            if [ -z "${arg/*]/}" ]
              then state=""
            fi
        elif [ "$arg" = "--" ]
          then state="input"
        elif [ -z "${arg/\[*/}" -a ! "$timespec" ]
        then
            timespec="$arg"
            if [ "${arg/*]/}" ]
              then state="time"
            fi
        elif [ -z "${arg/*@*/}" -o -z "${arg/*:*/}" ]
        then
            if [ -z "${arg/*@*/}" ]
            then
              if [ "${arg%%@*}" -a ! "$user" ]
              then
                user="${arg%%@*}" 
              fi
              if [ "${arg#*@}" -a ! "$host" ]
              then
                host="${arg#*@}"
                host="${host%%:*}"
              fi
            fi
            if [ -z "${arg/*::*/}" ]
            then
              if [ "${arg#*::}" -a ! "$argdir" ]
              then
                argdir="${arg#*::}"
                recursive_dir=0
              fi
            elif [ -z "${arg/*:*/}" ]
            then
              if [ "${arg#*:}" -a ! "$argdir" ]
              then
                argdir="${arg#*:}"
                recursive_dir=1
              fi
            fi
        else
            search+="${arg}.*"
        fi
    done

    if [ "$argdir" ]
    then
        if [ -z "${argdir##~*}" ]
        then directory="$(readlink -m -- "$HOME${argdir#\~}")"
        else directory="$(readlink -m -- "$argdir")"
        fi
    fi

    local start_time
    local end_time
    if [ "${timespec/*..*/}" ]
    then
      timespec="${timespec#[}"
      timespec="$(date -d "${timespec%]}" '+%F')"
      start_time="$timespec"
      end_time="$timespec + 1day"
    else
      start_time="${timespec%..*}"
      start_time="${start_time#[}"
      end_time="${timespec#*..}"
      end_time="${end_time%]}"
    fi

    if [ "$start_time" ]
    then
      start_time="$(date -d "$start_time" '+%F %T')"
      if [ -z "$start_time" ]
      then
        return 1
      fi
    fi
    if [ "$end_time" ]
    then
      end_time="$(date -d "$end_time" '+%F %T')"
      if [ -z "$end_time" ]
      then
        return 1
      fi
    fi

    if [ "$recursive_dir" = 0 ]
    then gawk -vdirectory="$directory" -vstart_time="$start_time" -vend_time="$end_time" -vsearch="$search" -vhost="$host" -vuser="$user" \
      'BEGIN { RS="\0"; FS="\t"; user_matcher="^"user"(@|$)"; host_matcher="[^@]*@"host;}
       { for(i = 5; i <= NF; i++) $4 = $4 "\t" $i}
       index($2,directory) == 1 && length($2) == length(directory) {
           if((length(start_time) == 0 || $3 >= start_time) &&
              (length(end_time) == 0 || $3 <= end_time) &&
              (length(user) == 0 || $1 ~ user_matcher ) &&
              (length(host) == 0 || $1 ~ host_matcher ) &&
              (length(search) == 0 || $4 ~ search )) printf "%s\t%s\t%s\t%s\0", $1,$2,$3,$4}' "$ALL_HISTORY_FILE"
    elif [ "$directory" = "/" ]
    then gawk -vdirectory="$directory" -vstart_time="$start_time" -vend_time="$end_time" -vsearch="$search" -vhost="$host" -vuser="$user" \
      'BEGIN { RS="\0"; FS="\t"; user_matcher="^"user"(@|$)"; host_matcher="[^@]*@"host;}
       { for(i = 5; i <= NF; i++) $4 = $4 "\t" $i}
       { if((length(start_time) == 0 || $3 >= start_time) &&
            (length(end_time) == 0 || $3 <= end_time) &&
            (length(user) == 0 || $1 ~ user_matcher ) &&
            (length(host) == 0 || $1 ~ host_matcher ) &&
            (length(search) == 0 || $4 ~ search )) printf "%s\t%s\t%s\t%s\0", $1,$2,$3,$4}' "$ALL_HISTORY_FILE"
    else gawk -vdirectory="$directory" -vstart_time="$start_time" -vend_time="$end_time" -vsearch="$search" -vhost="$host" -vuser="$user" \
      'BEGIN { RS="\0"; FS="\t"; user_matcher="^"user"(@|$)"; host_matcher="[^@]*@"host;}
       { for(i = 5; i <= NF; i++) $4 = $4 "\t" $i}
       index($2,directory) == 1 {
           if((length(start_time) == 0 || $3 >= start_time) &&
              (length(end_time) == 0 || $3 <= end_time) &&
              (length(user) == 0 || $1 ~ user_matcher ) &&
              (length(host) == 0 || $1 ~ host_matcher ) &&
              (length(search) == 0 || $4 ~ search )) printf "%s\t%s\t%s\t%s\0", $1,$2,$3,$4}' "$ALL_HISTORY_FILE"
    fi
}

_init_log_history () {
  local histline
  while read -r -d '' histline
  do _PWD+=( "$histline" )
  done < <( gawk 'BEGIN { RS="\0"; FS="\t"; }
                  { a[$2] = NR }
                  END { PROCINFO["sorted_in"] = "@val_num_desc";
                        num = 0;
                        for (i in a) { printf "%s\0", i; num++; if (num == 10) break } }' \
                  "$ALL_HISTORY_FILE" )

  local directory="$(pwd -P)"
  if [ "$directory" != "$_PWD" ]
  then
    local match
    local i
    for i in {1..8}
    do if [ "$directory" = "${_PWD[$i]}" ]
       then unset _PWD[$i]
            match="true"
       fi
    done
    if [ -z "$match" ]
    then unset _PWD[9]
    fi
    _PWD=( "$directory" "${_PWD[@]}" )
    local directory="${_PWD[1]}"
  fi
}
_init_log_history
  • 熟练掌握分屏技巧Mac用户自不必说,iTerm分屏:
    ⌘ + d: 垂直分屏。
    ⌘ + shift + d: 水平分屏。
    ⌘ + ]和⌘ + [在最近使用的分屏直接切换。
    ⌘ + opt + 方向键切换到指定位置的分屏。
    会了这些之后还有一个比较关键的就是多个窗口同时输入命令:alt + shift + i 这样右上角会显示一个图标,此时多个会话会同时输入命令。(包括不同tab)
    Windows用户必须熟练掌握Tmux,具体教程网上一搜一堆。我这里就提一句打开Tmux的时候上传下载要小心。
  • 熟练掌握光标移动命令
    如果你已经干了1-2年运维。登录服务器的时候还是在通过左右方向键在移动光标的话,真是应该反思了,在这里分享一张示意图。一线运维必备技能知识串讲(一)该示意图生动的描述了如何摆脱方向键实现光标的快速移动。如果你使用的命令行工具不兼容Alt相关的快捷键的话请自行实现键盘映射,比如我使用hhkb键盘把Alt-b和Alt-f改为fn-b和fn-f。

今天先聊到这里,后续会分享更多与各种场景相关的应对方案,让大家处理线上故障的时候更加得心应手。

上一篇:数据权限这样设计,你觉得如何?


下一篇:[20161228]linux修改网络配置问题.txt