vim

插入模式下
/           搜索内容
w           相当于Windows里的CTRL+S 及时保存
r           读取文件内容到当前光标位置  # : etc/passwd 
x           保存退出=wq
X           对文件加密  可以把机密的文件加密,如密码表等 
!           执行命令 # :!date     
r!          把命令结果输出到光标位置
set nu      显示行号   setnonu   不显示行号
set ai      自动对齐
set ic      忽略大小写
set ff      文本格式转换 # :set ff=dos  set ff=unix 
set cul     下划线功能
set list    查看不可见字符
set ts=4    把tab变成4个空格键
set expandtab #配合上调set ts 使用
y           复制 # :2+5 y
p           粘贴
d           删除 # :7,15 d
%           全文 #  :%d
s           搜索替换  # %s/哈哈/吧吧/g  吧全文的哈哈替换成baba
   # : 1,5s/haha/baba/g  把haha替换成baba(g是整行的   haha 个替换成baba)    也可以把"/"换成其他符号如 "@"  "#"

命令模式
ZQ          不保存退出 #等于 :q!
ZZ          保存退出   #等于 :wq 
h j k l     上下左右    #3h  5l  可以带数字移动
H M L       吧当前页光标位置至于屏幕最上方行,中间行,最下方行
zt zz zb    吧光标处移动到屏幕顶端,重间,最后显示
G gg 5G     跳到最后一行 第一行 第五行
ctrl+f b u d翻半屏,全屏 #相当于pageup pagedown
x           删除当前光标处字符(一个) #之后还可按p粘贴(一个)
~           转换大小写 #蛮实用的
dd yy 5dd   剪切当前行  复制当前行 剪切5行  P粘贴
/           搜索   所搜之后 # N n  向上搜索 向下搜索
u  U        撤销   撤销一次   U吧本行的所有操作全部撤销
ctrl+r      重做最后的撤销 # u完之后后悔了  ,用ctrl+r
di yi vi " ' { 剪切 复制 选中  " ' { 符号里的内容       '   
ctrl+w  s  v同文件多窗口显示  #ctrl+w+上下左右切换窗口  ctrl+w+q或o退出



可视化模式 v  V  ctrl+v  面对字符 ,整行  面对块
如何把文件里的每一行前加上"#"符号?
答
#输入ctrl+v 进入可视化模式
#输入 G 跳到最后1行,选中第一行
#输入 I 切换至插入模式
#输入 #
#按 ESC 键


替换模式
R           开启替换模式,输入的字符将替换原有光标处的字符 # ESC即退出模式


#可以在家目录里创建一个 .vimrc的配置文件,把默认的vim配置放里

hedxdump查看二进制文本
od查看文本二进制或八进制十六进制 # od /data/haha.txt -t x1z
xxd查看二进制的文本

less 文本翻页 #有时候输出的命令结果跑的太快,可以用less来分页查看
head 查看文件前几行 默认10行 # -n15 前15行
tail 查看文件后几行 # -F 跟踪文件名 -f 跟踪文件(描述符)
# -n+3 从第三行开始显示
cut 取列 # -d 指定分隔符 -f 选列
# -c 选取字段 # cut -c2-15 /etc/passwd
# --complement 取反,取选定列相反的字段

paste 合并文件 #无卵用 -d指定分隔符
diff 比较文件不同 #卵用不大
cmp 比较文件二进制不同 #无卵用
wc 文本统计 # -l统计行 -w 统计单词 -c 统计字节 -m统计字符

sort 排序 # -n正常十进制数字排序
# -r反方向排序
# -R随即排序
# -f忽略大小写
# -u删除重复的行(经测试 -nu 与-u 有区别)
# -t -k #指定分隔符,选取第几列 #-t ' ' -k5 已空格为分隔符,选第5列

uniq 删除重复行
# -c 显示重复次数
# -d 只显示重复过的行
# -u 只显示没重复过的行

seq 100 | sort -R |head -1 #一百个数字取一个随机数

三剑客

grep -o 只显示匹配到的内容
-p 不做输出 (但可通过$?查询执行成功或失败)
-i 忽略大小写
-v 取反
-n 显示行号
-e 表示或关系 #cat /etc/passwd |grep -e bash -e root 显示包含root跟 bash的行
-w 匹配整个单词 # 除了数字,字母,下划线.其余都是单词的分界符
-A B C 匹配结果 前 后 重间 的行 # grep -A3 haha 包含haha下三行的行
-E 扩展模式 配皮扩展正则表达式
-R 递归,处理软链接 # -r 不处理软链接
-f 根据模式处理文件 # 可以 比较两个文件的相同行
#例子
[root@20:21:27 data]78# cat >2.log
12
23
hahah
345
[root@20:21:53 data]79# cat 1.log 2.log
123
234
345
hahaha
12
23
hahah
345
[root@20:21:58 data]80# grep -f 1.log 2.log
345

正则表达式

. 表示任意单个字符 #匹配的是字符,不是自己,所以汉字也可以被匹配
[] []表示包含 #和通配符相同
[^] 取[]里面的反 #和通配符相同 #grep [av]以不是av开头的行

  • 出现0次或任意次 # hello l出现0次或任意次
    .
    任意字符串 #不是单个字符,不限制长度
    ? 单个字符出现0次或1次
    + 单个字符至少出现一次
    {1,3} 匹配前面字符至少1次,至多三次
    {} 匹配前面字符出现的次数# echo abcabcabc |grep 'c{1,3}'
    # 筛选c出现过1次到三次的行
    # echo abcabcabc |grep '(abc){3}'
    # 筛选abc出现过三次的行
    () 分组 # grep (haha) #吧haha作为一个分组
    #%s@(haha)@\1er@g #在vim里吧 haha替换成hahaer

\b 词首或词尾 #<词首 > 词尾
^ 行首
$ 行尾
| 或 # (C|c)at cat 或Cat
# a|b
# cat|b cat或b

练习 正则表达式

1、显示/proc/meminfo文件中以大小s开头的行(要求:使用两种方法)
#cat /proc/meminfo |grep -i '^s.*'
#cat /proc/meminfo |grep -i s |sort |tail |head -9
2、显示/etc/passwd文件中不以/bin/bash结尾的行
#cat /etc/passwd |grep -v  /bin/bash$
#cat /etc/passwd |grep -v 'bin/bash\b'
3、显示用户rpc默认的shell程序
#getent passwd  rpc  | cut -d ':' -f7
#/bin/bash
4、找出/etc/passwd中的两位或三位数 (找出系统用户的UID用数字来搜索)
#grep -Eo "[0-9]{2}|[0-9]{3}" /etc/passwd 
#有瑕疵,四位数字的标识出来了三位
5、显示CentOS7的/etc/grub2.cfg文件中,至少以一个空白字符开头的且后面有非空白字
符的行
#cat /etc/grub2.cfg |grep  ^[[:space:]]   只完成了一半

6、找出“netstat -tan”命令结果中以LISTEN后跟任意多个空白字符结尾的行
#netstat -tan |grep -o 'LISTEN[[:space:]]*'
7、显示CentOS7上所有UID小于1000以内的用户名和UID
#getent passwd |sort -t: -k3 -nr |tail -n+11 |cut -d : -f1,3 |tr ':' ' '
8、添加用户bash、testbash、basher、sh、nologin(其shell为/sbin/nologin),找出/etc/passwd用户名和shell同名的行
#?????
9、利用df和grep,取出磁盘各分区利用率,并从大到小排序
#df |grep ^/dev |tr -s ' ' '%' |cut -d % -f5|sort -nr |head -1

扩展
1、显示三个用户root、mage、wang的UID和默认shell
#getent passwd |grep -w -e ^root -e ^dachui -e ^tomcat |cut -d : -f3,7 |tr ':' ' '
2、找出/etc/rc.d/init.d/functions文件中行首为某单词(包括下划线)后面跟一个小括号的行
#
3、使用egrep取出/etc/rc.d/init.d/functions中其基名
#
4、使用egrep取出上面路径的目录名
#
5、统计last命令中以root登录的每个主机IP地址登录次数
#last |grep   ^root.* |grep -v tty1 |tr -s ' '| cut -d ' ' -f3 |sort | uniq -c |sort -nr |head -1
6、利用扩展正则表达式分别表示0-9、10-99、100-199、200-249、250-255
# [1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]
# 判断一个IP是不是合法IP :
                           [[ $IP =~  ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]
7、显示ifconfig命令结果中所有IPv4地址
# ifconfig | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}'
# 但吧其他的信息也匹配出来了子网掩码
8、将此字符串:welcome to magedu linux 中的每个字符去重并排序,重复次数多的排到前面
#


shell脚本

脚本须符合shebang机制  即  #!/bin/bash   
大部分情况下,脚本需要加执行权行才可以运行   chmod+x    XXX.sh
可以有四种方法运行脚本   #管道的方法,吧脚本传给bash
                        #吧文件路径添加到PATH变量里
                        #加执行权限,用绝对路径或相对路径发
                        #bash  加脚本 #不需要有执行权限
                        #source加脚本 #不需要执行权限
    #bash 是相当于开启一个子进程执行脚本,source相当于在当前进程执行脚本
    #相对来讲bash更安全一些,source容易修改当前的变量
                           #在修改配置文件的时候才建议使用source执行脚本


脚本的常见错误   #语法错误     语法出错后续行不会继续执行  
                #逻辑错误     系统判断不出逻辑错误
                #命令错误     命令出错会继续执行后续行命令
可以用 bash -n 检查语法错误  
                #只是检查脚本中的语法,并不执行脚本
可以用 bash -x 检查命令执行过程 #逐行执行,并显示执行过程
                #执行脚本并逐行显示执行的过程

变量可已存放命令比如
                       HAHA=date
                       [root@21:22:24 ~]145# $HAHA
                       Thu Apr  2 21:22:30 CST 2020  
变量可以是很多种方式比如 : NAME=li
                           NAME=`whoami`
                           NAME=$USER
                           NAME=/etc/*
                           NAME="wang  
                                 li 
                                 zhao
                                 qian"
 $_存放的是前一个命令的最后一个参数
 $-存放系统的关键字
 $$是自己当前shell的PID
 $PPID是父进程的ID


   注意区别:
   HAHA=`seq 5`
   [root@13:27:59 ~]71# echo $HAHA
   1 2 3 4 5 
   [root@13:28:04 ~]72# echo $"HAHA"
   HAHA
   [root@13:28:10 ~]73# echo "$HAHA"
   1
   2
   3
   4
   5

   注意区别:
   [root@13:35:33 ~]77# QQQ=123
   [root@13:35:41 ~]78# WWW=$QQQ
   [root@13:35:48 ~]79# echo $QQQ
   123
   [root@13:35:52 ~]80# echo $WWW
   123
   [root@13:35:57 ~]81# QQQ=456
   [root@13:36:05 ~]82# echo $QQQ
   456
   [root@13:36:07 ~]83# echo $WWW
   123
   [root@13:36:20 ~]86# unset QQQ
   [root@13:36:32 ~]87# echo $QQQ

   [root@13:36:33 ~]88# echo $WWW
   123

   为什么因为变量里的"="是赋值的意思不是等于号的意思,WWW的值赋值给了$QQQ也就是123,所以$QQQ改变凉了$WWW也是123,即使变量$QQQ被删除,也不会影响$WWW的值!

数字不可以作为变量名# 1=haha echo$1
下划线可以作为变量名称,下划线不可以作为主机名
横线可以作为主机名,横线不可以做为变量名
#echo $NAME_$AGE
#20
#echo ${NAME}_$AGE
#mage_20

普通变量无法在子进程或父进程使用 只能在当前终端使用 #脚本调用脚本也不继承
在自身进程里的变量优先级高于父进程的变量(如果重名的话)



export 可以声明环境变量  #
                        # export  HAHA=baba
                  或者  # HAHA=baba    # export HAHA
true 返回一个成功状态码
false返回一个错误状态码
set查看所有变量
set --清空位置变量
set -o 查看一些set的参数   #set -o  xxx=on/off
set -e 当脚本中有一条命令出错后,就会停止执行脚本(只针对命令?)
set -u 如果脚本中存在没定义的变量,则不允许运行脚本
env即可查看所有的环境变量
readonly定义只读变量  exit当前窗口即可删除只读变量  只读变量只对当前窗口有效

位置变量   $0 $1 $2 $@ $*
          #$0表示自身(命令和路径)
          #$!表示第一个参数  $2表示第二个参数  $45表示第45个参数
          #$@ 表示全部参数 #如果存在嵌套脚本,"$@"表示全部的独立参数
          #$*表示全部参数  #如果存在嵌套脚本,"$*"表示把全部的参数当成一个参数
      #   $#显示本脚本参数的个数
注意:$@ $* 只在被双引号包起来的时候才会有差异      
注意:如果想表示$45变量需要把45括起来,否则显示成$4加上字符5  #${45}才能表示出来

$?状态码 (只能查询上一条的执行结果) 
         #0表示上一条命令执行成功                  
         #1-255表示执行失败
echo $?
0

print 相当于高级版本的echo #个人感觉用处不大

bash运算

let 
$[]    echo -e "\e[1;$[RANDOM%7+31]mhello world\e[0m"  #实现随机颜色
$(())
expr  #    expr    2 \* 3     3 - 1   #只能取整数,且不支持浮点数
$( arg1 arg2 arg3 )
echo   xxx |bc 

与或非

与或非 true是1 false是0
$?里 1是上个命令执行失败 0是执行成功
变量互换
# i=10;j=20;k=$i;i=$j;j=$k;echo $i $j
i=20;j=10
# i=10;j=20:i=$[ij];j=[ij];i=[i^j];echo %i $j
i=20;j=
###异或三次可以实现两个值互换,就不需要第个那样的传统方法了

脚本

比较的命令:
       test # test -a   xxx  
       []   # [ $I -eq  $Q  ]
       [[]] #支持正则表达式跟通配符 #[[ 条件 =~ 正则]] [[ 条件 == 通配符 ]]
            #注意需要转义 # [[ $FILE =~ \.log$ ]] (匹配.log结尾的文件)
            #注意是匹配的扩展正则表达式 
数值判断:   (只能用于数字判断)
 # -eq 等于
 # -ne 不等于
 # -gt 大于
 # -ge 大于等于
 # -lt 小于
 # -le 小于等于
 # $SRT1 = $STR2 判断字符串是否相等(内容) 
 # $SRT1 != $STR2 判断字符串是否不等(内容) 
字符串测试:
#  = 是否字符串两边相等
# != 是否字符串两边不等
# == 用于[[]]匹配通配符模式
# =~ 用于[[]]匹配正则表达式
状态判断:
 # -v 判断变量是否存在,(空也被判定为true)#(-R 也是判断变量是否存在,空则反馈false)
 # -a 判断文件是否存在
 # -b 判断是不是块文件
 # -c 判断是不是字符文件
 # -d 判断是不是文件夹
 # -e 判断文件是否存在
 # -f 判断是不是普通文件
 # -z  字符串是空 (没定义或者是空值)
 # -n  字符串非空                         
 # -s 判断存在且大小大于0
 # -h 判断是不是软链接
 # -L 判断是不是软链接
                     # (判断软链接时,判断的是软链接指向的文件,如指向的件  是普通文件,则判定为普通文件)
权限判读:                     
 # -r 判断文件是否有r权限
 # -w 判断文件是否有w权限
 # -x 判断文件是否有x权限
                     # [ -x "aa.txt" ] 判断aa.txt文件是不是又x权限
                     # 根据实际权限来判定,不见得是LL看见的文件权限
 
 # () 开启一个子进程并执行()里的内容 #()里的变量不影响当前进程变量
                                    #()可已继承父进程变量
 # {} 不开启子进程,在当前进程执行{}里的内容 #{}里的变量影响当前进程变量
                                    #(){}都可以将多个命令组合到一起执行,但结果不同
组合写法:[]
 # -a  并且           
                    # [ -f "$FILE" -a -x "$FILE" ] # $FILE文件是否是普通文件,并且具有执行权限 #条件全部满足就反馈true
 # -o  或           
                    # [ -f "$FILE" -o -x "$FILE" ] # $FILE文件是否是普通文件,或者$FILE是否具有执行权限  #满足一个条件就反馈true
 # !   取反          
                     #  ! [ -d /etc]    echo $?  1 
                     #  [ ! -d /etc ]  两种写法都一样

# -a -o  只支持[]写法 [[]]不支持此写法

组合写法: && ||

 # && 短路与   # id wang &> /dev/null && echo " $ID exits "
 # || 短路或

比较[[]]的注意事项
在比较时[] | [[]] 内必须要有空格,如没有,则会被判定为变量赋值
为避免在[] | [[]] 是出现错误,建议在[] | [[]] 左侧变量加上""
# 在 [[ $"XX" == 通配符 ]] 右侧通配符加""只代表 ""里的内容本身,不带有其他含义
# 或者[[ "$XX" == 通配符]] 只想作为内容本身,也可以转义

判断一个IP是不是合法IP:

[[ "$IP" =~ ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]
判断是不是一个数字:
[[ "$XXX" =~ [1]+$ ]]
判断是不是一个后缀:
[[ "$XX" == *.log ]] # == 用法似乎不需要转义

IF CASE

IF:
  语法 if      CMD1   ;then
                           CMD2
          elif CMD3   ;then
                           CMD4 
          else CMD5 
       fi              

case:
  语法 case变量引用 in 
          PAT1)
              分支1
          ;;
          PAT2)
              分支2
          ;;
          *)
              默认分支
          ;;
       esac

例子:
#!/bin/bash
#alone test
read -p "are you alone? (input y/n)"  ANS
    case  $ANS in
            [Yy]|[Yy][Ee][Ss])
                        echo "you are alone"
                                          ;;
             [Nn]|[Nn][Oo])
                        echo "you are not alone"
                                          ;;
                         *)
                        echo "wrong input"      
    esac


#!/bin/bash
#alone test 
read -p "are you alone?(input y/n)"  ANS

        if [[ $ANS =~ [Yy]|[Yy][Ee][Ss] ]] ;then
                                       echo "you are alone"
           elif [[ $ANS =~ [Nn]|[Nn][Oo] ]]  ;then
                                       echo "you are not alone"
              else echo "worng in put exit"
                            exit 100
        fi




()跟{}的区别

#AA=dachui ; (echo $AA ;AA=xiaochui ; echo $AA); echo $AA 输出的结果?
      dachui
      xiaochui
      dachui
#小括号默认开启了一个子进程,子进程的变量无法影响父进程
#()里的变量可已从父进程继承,无需定义成环境变量 #小括号的特性


#AA=dachui ; { echo $AA ;AA=xiaochui ; echo $AA; }; echo $AA输出的结果?
      dachui
      xiaochui
      xiaochui
            #{}的使用方法是 {}里的内容与括号本身用空格隔开,且最后结束前加; 即{ XX   XX; }      
            #{}不开启子进程,花括号里的变量影响当前进程的变量

shell脚本里如果定义的一个变量是命令,千万记得加``不然不生效

read

read 可以给变量赋值 如果没输入变量名称,默认把输入的内容存入$REPLA变量里
# read
haha
echo $REPLA
haha
# read AA
wawa
echo $AA
wawa
# read可以一次给多个变量赋值
# read a b
xx yy
echo $a $b
XX YY
read -p 不换行并且加提示 #很常用
read -s 静默输入 (长用于密码)
read -t timeout时间 #read -t 35 #35秒不进行输入则超时
read -n 指定输入的字符长度

配置文件

配置文件分为全局配置和个人配置,全局配置都放在/etc/目录下,个人配置方在~目录下
已下几个文件可以影响bash的配置
全局配置:
/etc/profile
/etc/profile.d/*.sh #即/etc/profile.d/任何已.sh结尾的文件
/etc/bashrc
个人配置:
~/.bash_profile #登入时执行
~/.bashrc #登入时执行
~/.bash_logout #退出时执行此脚本
通常来讲建议吧配置文件方在/etc/profile.d/文件夹下自建一个.sh的文件,此法不修改系统的配置文件,而且无论su还是su - 都需要读取此文件,此文件不用及删非常方便

profile与bashrc的区别:
profile:存放环境变量跟脚本
bashrc:存放普通变量跟别名

#Ubutun的PS1变量建议方在profile文件中


  1. 0-9 ↩︎