• Linux Shell 脚本语法以及常用命令


    /etc/passwd

    是一个多行多列的表格,列的分隔符号是冒号

    root:x:0:0:root:/root:/bin/bash 
    用户名:以前是密码,现在x是加密放到shadow:用户id:组id:
    用户描述:home目录地址:用户登入之后执行的第一条命令
    如果用户启动的第一条命令不是shell的话,那么执行完命令就会退出
    mon:/usr/sbin:/usr/sbin/nologin,这个就不能登入。
    
    • 1
    • 2
    • 3
    • 4
    • 5

    确定当前shell

    echo $SHELL  查看环境变量
    看passwd文件用户的启动命令
    修改当前用户的shell: chsh
    
    • 1
    • 2
    • 3

    shell的内建命令

    • 查看 man bash-builtins
    • shell的内建命令是不会启动进程的,而是就在当前shell的进程下去调用一个函数,执行后返回一个状态码,非内建的本质就是fork,然后exec启动一个进程。

    执行脚本

    #!/bin/bash
    # 第一行表示解释器,表明使用的sh解释器
    echo HelloWorld
    cd .. #这里是子shell进程执行,子shell进程工作目录变化,父shell进程不会受影响
    ls
    
    • 1
    • 2
    • 3
    • 4
    • 5

    执行脚本:

    chmod a+x a.sh
    ./a.sh # 需要可执行权限
    sh a.sh # 需要可读权限,不用可执行权限,在一些没办法调整脚本权限的情况下使用,和第一种方法类似
    # 有一个弊端:要调用者关注当前脚本使用的解释器
    source a.sh
    . a.sh
    # 上面的两种都是使用内建命令来执行的,不会创建子shell进程。就在当前shell进程执行。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    基本语法

    变量

    shell变量通常由字母加下划线开头,由任意长度的字母、数组、下划线组成。
    赋值一个变量: VARNAME=value注意等号两边不能由空格,否则会被shell解释成命令和命令行参数。
    变量的使用,用$符号跟上变量名表示对某个变量取值,变量名可以加上花括号表示变量名的范围echo $VARNAME, echo ${VARNAME}_suffix。使用花括号来分离,不至于将VARNAME_suffix当作一个变量。

    变量的分类

    • shell 内变量:在shell的解析环境中存在的变量,分为局部变量全局变量。shell不适用任何修饰符修饰的变量都是全局变量,不管在函数内部还是外部,生命周期从声明语句调用开始一直到shell结束。局部需要使用local修饰,只能声明在函数内部,生命周期从声明语句调用开始一直到函数结束。shell内变量只能在当前shell进程中使用,垮了进程就不能使用
    #!/bin/bash
    globalVar1="Hello" # 全局变量
    function test() # 在sh解释器中没有function关键字,在bash中有,所以funcuton关键字可以省略掉
    {
        globalVar2="world" # 全局变量
        local localVar1="itcast" # 局部变量
        echo ${localVar1} # itcast
    }
    test
    echo ${globalVar1} ${globalVar2} ${localVar1} # 输出结果 Hello world 局部变量不存在
    ./subscript.sh # 不会将全局变量传递过去,他们是两个进程
    source subscript.sh # 他们是同一个进程,可以在子脚本中使用该全局变量,会打印出Hello
    
    # sub script
    #!/bin/bash
    echo "this is a sub script"
    echo ${globalVar1}
    echo "sub script end"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 环境变量:是操作系统自带的,每一个进程都会有。当启动一个子进程的时候,环境变量是从父进程拷贝到子进程的。可以用于进程间、脚本间传递参数。环境变量是单向传递的,子进程做任何环境变量的修改,都不会影响父进程
    export varname=value # 将varname添加到环境变量
    varname1=value
    export varname1 # 将varname1添加到环境变量
    
    #!/bin/bash
    envVar="hello world"
    export $envVar
    # 调用子脚本
    ./subScript.sh # 输出 hello world
    # 验证子进程中修改环境变量,父进程有没有改变
    echo $envVar # 输出 hello world 子进程环境变量不会改变父进程的
    
    # subScript.sh
    #!/bin/bash
    echo ${envVar}
    export envVar="2222222222"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    删除变量unset

    不管是环境变量还是普通的shell变量,都可以使用unset关键字进行删除。

    unset varname
    
    • 1

    文件名代换*/?/[]

    文件名代换,也就是 Globbing 。使用匹配的字符,也就是通配符。代换发生在命令执行之前。代换的前提是文件存在,不存在代换不了。

    • ***** :匹配 0 个或多个任意字符 *.txt
    • ?:匹配任意一个字符 ?.txt
    • [若干字符]:匹配方括号中任意一个字符的一次出现, R[0-8]_[8-7]

    参数扩展{}

    # 下面的功能是一样的,都是创建1到4的txt文件 
    touch 1.txt 2.txt 3.txt 4.txt
    touch {1..4}.txt
    touch {1,2,3,4}.txt
    
    mkdir -p day{1..9}/0{1_code,2_doc,3_resource,4_node}
    # 创建day1到9的文件夹,并且每个文件夹中都有01_code,02_doc,03_resource,04_node四个文件夹。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    命令代换``/$()

    使用"`"反引号括起来的也是一条命令,shell先执行该命令,然后将输出结果立即代换到当前命令中。执行某一条命令,将这个命令的标准输出的内容存储到某个变量中。

    DATE=`date`
    echo ${DATE}
    DATE=$(date) # 和反引号的功能是一致的
    # 获取当前脚本的所在目录
    curPath=$(cd `dirname $0`;pwd)
    # cd `dirname $0` 是进入脚本所在的目录
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    算术代换 ( ( ) ) / (())/ (())/[]

    使用$(()),用于算术计算,(())中的shell变量取值将转换成整数,和同样含义的$[]等价。

    VAR=45
    echo $(($VAR+3)) 等价于 $((VAR+3)) 或者 echo $[VAR+3]或 $[$VAR+3]
    
    • 1
    • 2

    他们只能使用+ - * /()运算符,并且只能做整数运算$[base#n],其中base表示进制, n按照base进制进行解释,后面再有运算数,按十进制解释。

    echo $[8#10+11] #输出 19
    echo $[16#10+11] #输出 27
    
    • 1
    • 2

    转移字符\

    \在shell中用作转移字符,用于去除紧跟其后的单个字符的特殊意义(回车除外),换句话说,紧跟其后的字符取字面值。

    echo \$SHELL # 输出$SHELL
    touch \$\ \$ # 创建$ $为名的文件
    
    • 1
    • 2

    单引号’’

    单引号用于保持引号内所有字符的字面值,即使引号内的\和回车也不例外,但是字符串中不能出现单引号。

    echo '$SHELL' # 输出$SHELL
    echo 'ABC\
    DE' # 输出ABC\回车DE
    
    • 1
    • 2
    • 3

    双引号""

    和单引号一致,但他防止通配符的扩展,允许变量的扩展。被双引号括住的内容,被视为单一字符串。

    echo "$SHELL" # 输出 /bin/bash
    var="a.txt b.txt"
    touch $var # 创建两个文件 a.txt和b.txt
    touch "$var" # 创建一个文件 名字为 a.txt b.txt
    
    • 1
    • 2
    • 3
    • 4

    脚本语法

    条件测试test/[

    Shell 条件测试 test 用于在脚本中根据条件检查执行分支。test 命令通常以 [ ] 或者 [[ ]] 的形式出现。直接使用某条命令的返回状态表示真假,main函数返回0表示真,返回非0表示假。

    1. 检查文件是否存在:

      • [ -e 文件路径 ]:如果文件存在,则返回 true。
      • [ -f 文件路径 ]:如果文件存在且为普通文件,则返回 true。
      • [ -d 目录路径 ]:如果目录存在,则返回 true。
    2. 数值比较:

      • [ 数值1 -eq 数值2 ]:如果两个数值相等,则返回 true。
      • [ 数值1 -ne 数值2 ]:如果两个数值不相等,则返回 true。
      • [ 数值1 -lt 数值2 ]:如果数值1小于数值2,则返回 true。
      • [ 数值1 -le 数值2 ]:如果数值1小于或等于数值2,则返回 true。
      • [ 数值1 -gt 数值2 ]:如果数值1大于数值2,则返回 true。
      • [ 数值1 -ge 数值2 ]:如果数值1大于或等于数值2,则返回 true。
    3. 字符串比较:

      • [ 字符串1 = 字符串2 ]:如果两个字符串相等,则返回 true。
      • [ 字符串1 != 字符串2 ]:如果两个字符串不相等,则返回 true。
      • [ -z 字符串 ]:如果字符串为空,则返回 true。
      • [ -n 字符串 ]:如果字符串非空 nonzero,则返回 true。
    4. 逻辑判断:

      • [ 表达式1 -a 表达式2 ]:逻辑与 and,如果两个表达式都为 true,则返回 true。
      • [ 表达式1 -o 表达式2 ]:逻辑或 or,如果两个表达式中至少有一个为 true,则返回 true。
      • [ ! 表达式 ]:逻辑非,如果表达式为 false,则返回 true。

    注意:[[ 支持更多的高级特性,比如模式匹配和正则表达式,推荐在使用条件测试时使用 [[ ]]。更详细的用法可以查看 Shell 的官方文档或者使用 man test 命令查看 test 命令的帮助文档。

    echo $? # 打印上条命令的返回状态,0为真,1为假
    ( EXPRESSION ): 测试该表达式是否为真
    ! EXPRESSION:取反,逻辑非
    EXPRESSION1 -a EXPRESSION2:and 逻辑与
    EXPRESSION1 -o EXPRESSION2:or 逻辑或
    -n STRING:nonzero, 判断字符串长度为非零
    -z STRING:zero, 判断字符串长度为零
    STRING1 = STRING2:判断字符串相等
    STRING1 != STRING2:判断字符串不相等
    INTEGER1 -eq INTEGER2:两个数值相等
    INTEGER1 -ge INTEGER2:判断数值1大于等于数值2
    INTEGER1 -gt INTEGER2:判断数值1大于数值2
    INTEGER1 -le INTEGER2:判断数值1小于等于数值2
    INTEGER1 -lt INTEGER2:判断数值1小于数值2
    INTEGER1 -ne INTEGER2:两数值不相等
    FILE1 -ef FILE2:FILE1 and FILE2 have the same device and inode numbers
    FILE1 -nt FILE2:判断文件1比文件2新(最后修改时间)
    FILE1 -ot FILE2:判断文件1比文件2旧(最后修改时间)
    -b FILE:block,判断文件为块设备
    -c FILE:character,判断文件为字符设备
    -d FILE:directory,判断是否为目录
    -e FILE:exist 判断文件是否存在
    -f FILE:判断文件为普通文件
    -g FILE:是否拥有有效组ID
    -G FILE:FILE exists and is owned by the effective group ID
    -h FILE:判断是否为一个符号链接 link
    -k FILE:判断粘着位是否设置
    -L FILE:判断是否为一个符号链接 link
    -N FILE:判断文件最后一次读取后文件的长度是否大于0
    -O FILE:判断文件是否有有效的用户ID
    -p FILE:是不是命令管道
    -r FILE:是否有读权限
    -s FILE:判断文件大小是否大于0
    -S FILE:判断文件是不是Socket文件
    -t FD : 判断文件描述符是否被终端打开
    -u FILE:判断文件用户ID是否被设置
    -w FILE:判断文件是否有写权限
    -x FILE:判断文件是否有可执行权限
    
    • 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

    if分支结构

    # 语法结构
    if 命令/条件测试
    then
    	xxxxxx
    elif 命令2/条件测试2 ; then # 如果then和if写在同一行需要加分号
    	xxxxxx
    else # else不用加then
    	xxxxxx
    fi # 将if倒着写
    
    #!/bin/sh
    if [ -f /bin/bash ]; then
        echo "/bin/bash is a file"
    else
        echo "/bin/bash is not a file"
    fi
    
    # ":",是一个空命令,总是为真
    if : # 等价于 if true
    then
    	echo "always true"
    fi
    
    echo "Is it morning? Please answer yes or no."
    read YES_OR_NO # 在终端输入一行字符串,保存到变量YES_OR_NO中
    if [ "${YES_OR_NO}" = "yes" ]; then
        echo "Good Morning"
    elif [ "${YES_OR_NO}" = "no" ]; then
        echo "Good Afternoon!"
    else
        echo "Sorry, ${YES_OR_NO} is not a recognized, Enter yes or no."
    fi
    
    ## 在shell中 && 和 || 用于连接两条命令,分别代表逻辑与和逻辑或
    ## 而-a 和 -o是仅用于条件测试中来连接两条测试命令的。下面是等价的
    VAR=2
    test "$VAR" -gt 1 -a "$VAR" -lt 3
    test "$VAR" -gt 1 && test "$VAR" -lt 3
    VAR=2
    if [ "$VAR" -gt 1 ] && [ "$VAR" -lt 3 ]; then
        echo "true"
    fi
    if [ "$VAR" -gt 1 -a "$VAR" -lt 3 ]; then
        echo "true"
    fi
    # 短路特性
    make && make install # 如果make执行失败,那么不执行make install
    echo xxx || exit -1 # 如果xxx执行失败,那么执行exit -1命令
    
    • 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

    case分支结构

    case … esac 为多选择语句,与其他语言中的 switch … case 语句类似,是一种多分支选择结构,每个 case 分支用右圆括号开始,用两个分号 ;; 表示 break,即执行结束,跳出整个 case … esac 语句,esac(就是 case 反过来)作为结束标记。可以用 case 语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。

    # 语法结构
    case 表达式 in
    val1|pattern1)
    	xxxx
    	;;
    val2|pattern2)
    	xxxx
    	;;
    *)
    	xxxx
    	;;
    esac # 将case倒着些
    
    
    #!/bin/bash
    echo "Is it morning? Please answer yes or no"
    read ANSWER
    case "$ANSWER" in
    yes|Y|y|YES|Yes)
        echo "Good Morning";;
    [nN][Oo]) # 代表组合no|nO|No|NO
        echo "Good Afternoon";;
    *)
        echo "Sorry, no recognized";;
    esac
    
    • 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

    for循环

    # 语法结构
    for 临时变量 in 列表; do
    	xxxxx
    done
    
    for fruit in apple banana pear; do # do 可以单独写一行,那么就可以不需要分号了
    	echo "$fruit"
    done
    sum=0
    for i in {1..100} # 循环加1-100 使用sh解释器没有花括号,使用 $(seq 1 100) 替换
    do
    	sum=$[$sum+i]
    done
    echo $sum
    # 遍历当前目录
    for i in $(ls)
    do
    	if [ -f "$i" ]; then
    		echo "$i is a file"
    	elif [ -d "$i" ]; then
    		echo "$i is a dir"
    	else
    		echo "$i no recognized"
    	fi
    done
    
    • 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

    while循环

    while 命令/条件测试 ;do # do 可以单独写一行,那么就可以不需要分号了
    	xxxxx
    done
    
    sum=0
    count=1
    while [ $count -lt 100 ]; do
    	sum=$(($sum+$count))
    	count=$(($count+1))
    done
    echo "sum = $sum"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    break/contine

    他们的意义和c/c++的是一致的。

    break[n] # 跳出几层循环
    continue # 跳过本次循环,但不会跳出循环
    
    #!/bin/sh
    echo "input passwd"
    read try
    count=1
    while [ "$try" != "passwd" ]; do
    	if [ $count -gt 5 ]; then # 等价于在while条件测试中添加 -a $count -gt 5
    		break
    	fi
        echo "sorry! try against"
        count=$(($count+1))
        read try
    done
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    位置参数和特殊变量

    有很多特殊变量是被shell自动赋值的

    $0  # 相当于C语言main函数的argv[0]
    $1$2... # 相当于C语言main函数的argv[1]、argv[2]....
    $# # 相当于C语言main函数的argc-1
    $@ # 表示参数列表 "$1" "$2" "$3" ... 可以用在for循环中的in的后面
    $* # 表示参数列表 "$1" "$2" "$3" ... 和$@一致
    $? # 表示上一条命令的Exit Status
    $$ # 当前进程号
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    位置参数可以使用shift命令左移。比如shift 3表示原来$4现在变成了$1,原来的$5现在变成了$2等等。原来的$1$2$3被丢弃,$0不移动。不带参数的shift命令相当于shift 1。也就是说shift语句和shift 1是等价的。位置参数最多只支持$0-$9,所以要后面的参数,就必须shift

    # ./shift.sh one two three four
    #!/bin/sh
    echo $$  # 169273
    echo $@  # one two three four
    echo $#  # 4
    echo $?  # 0
    echo $0  # ./shift.sh
    echo $1  # one
    echo $2  # two
    echo $3	 # three
    shift 1
    echo $3	 # four
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    输入输出

    echo [option] string
    -e 解析转义字符
    -n 不回车,默认情况下echo回显内容后面跟一个回车换行
    echo -e "hello\t123"
    echo -n "hello"
    printf "%d\t%s\r\n" 123 "hello"  # 123	hello
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    管道

    通过|命令把一个命令的输出传递给另一个命令做输入。原理为将前面的进程的标准输出重定向到后面进程的标准输入。

    cat filename | grep "hello"
    cat myfile | more
    
    • 1
    • 2

    tee

    tee命令把结果输出到标准输出,另一个副本输出到相应的文件。

    df -k | awk '{print $1}' | grep -v "文件系统" | tee a.txt
    df -k | awk '{print $1}' | grep -v "文件系统" | tee -a a.txt # -a表示追加到a.txt后
    
    • 1
    • 2

    文件重定向

    cmd > file  # 把标准输出重定向到新文件中
    cmd >> file # 最加到文件中
    cmd > file 2>&1 # 标准输出重定向到file文件
    			# 文件描述符2标准错误输出重定向到文件描述1标准输出中。
    cmd < file1 > file2 # 将标准输入重定向到file1,也就是file1作为标准输入 标准输出重定向到file2
    cmd < &fd # 把文件描述符fd作为标准输入
    cmd > &fd # 把文件描述符fd作为标准输出
    cmd < &-  # 关闭标准输入
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    函数

    function 函数名() # 在sh解释器中没有function关键字,必须省略
    {
    	local var=value # 局部变量
    	xxxx
    	retrun 0 # 只能返回整数,作为退出状态,不能返回其他,
    			# 也可以不写retrun返回,那么就以函数最后一条指令返回状态作为整个函数的退出状态
    }
    # 在bash解释器中,function和小括号可以省略,但是必须要有一个存在,不然无法识别为函数。
    # 调用函数 函数名 arg1 arg2 arg3 ... 
    
    testfunction()
    {
    	echo "aaaa"
    	return 2 # 那么此时echo $? 就是2
    }
    # 使用命令代换的方式获取函数的输出值aaaa
    var=$((testfunction))
    
    # 函数传参
    # 在函数的内部同样是通过 $0 $1 $2 $3 .. 来获取参数
    # 函数支持递归,遍历整个目录
    visit()
    {
    	local dir="$1" # 获取当前目录
    	for f in `ls $dir` 
    	do
    		if [ -f "$dir/$f" ]; then
    			echo "$dir/$f is a file"
    		elif [ -d "$dir/$f" ]; then
    			echo "$dir/$f is a dir"
    			visit "$dir/$f"  # 递归进行遍历
    		else
    			echo "$dir/$f is not regcognized"
    		fi
    	done
    }
    
    • 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

    Shell脚本的调试方法

    -n 读一遍脚本的命令但不执行,用于检查脚本中的语法错误
    -v 一边执行脚本,一边将执行过的脚本命令打印到标准错误输出
    -x 提供跟踪执行信息,将执行的每一条命令和结果依次打印出来
    
    sh -n script.sh # 在命令行提供参数
    # 在脚本开头提供参数
    #!/bin/sh -x 
    # 在脚本中使用set命令启动或者禁用参数
    set -x # 打开调试
    set +x # 关闭调试
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    正则表达式

    一种匹配字符串的方法,通过一些特殊符号,实现快速查找、删除、替换某个特定字符串。是由普通字符与元字符组成的文字模式。

    • 基础正则表达式
    元字符作用
    \转义字符,用于取消特殊字符的含义,例如:\!\n
    ^匹配字符串开始的位置,如:^hello,匹配以hello开头的行
    $匹配字符串结束的位置,如:hello$,匹配以hello结尾的行
    .匹配除了\n换行之外的任意一个字符
    *匹配前面子表达式0次或者多次
    [list]匹配list列表的一个字符,[0-9]匹配0-9的任意一个数字
    [^list]匹配不在list列表的一个字符,[^0-9]匹配任意非数字
    {n}匹配前面的表达式n次,[0-9]{2}匹配2位数字
    {n,}匹配前面的表达式不少于n次,[0-9]\{2,}匹配2位以上的数字
    {n,m}匹配前面的表达式n到m次,[a-z]{2,3}匹配2到3位的小写字母
    • 扩展正则表达式(在基础上面将+?等作为特殊字符)
    元字符作用
    +匹配前面子表达式一次以上,go+d,将匹配至少一个o
    ?匹配前面子表达式0次或者一次,go?d,匹配gd或者god
    ()将括号中的作为一个整体,g(oo)+d,匹配整体一次以上,例如goodgooood
    ``
    • perl正则表达式

    在扩展正则表达式的上面添加了一些特殊字符,是最常用的。

    \d	匹配一个数字的字符,和 [0-9] 语法一样
    \d+	匹配多个数字字符串,和 [0-9]+ 语法一样
    \D	非数字,其他同 \d
    \D+	非数字,其他同 \d+
    \w	英文字母或数字的字符串,和 [a-zA-Z0-9_] 语法一样
    \w+	和 [a-zA-Z0-9_]+ 语法一样
    \W	非英文字母或数字的字符串,和 [^a-zA-Z0-9_] 语法一样
    \W+	和 [^a-zA-Z0-9_]+ 语法一样
    \s	空白符号,和 [\n\t\r\f] 语法一样
    \s+	和 [\n\t\r\f]+ 一样
    \S	非空白符号,和 [^\n\t\r\f] 语法一样
    \S+	和 [^\n\t\r\f]+ 语法一样
    \b	匹配以英文字母,数字为边界的字符串
    \B	匹配不以英文字母,数字为边界的字符串
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • grep查找命令选项
    命令作用
    -n显示行号
    -i不区分大小写
    -v反向查找
    以S开头的字符串:^S
    以数字结尾的字符串:[0-9]$
    匹配空字符串:^$
    字符串只包含三个数字:^\d\d\d$  ^[0-9]{3}$ ^\d{3}$
    字符串只有3到5个字母:^[a-zA-Z]{3,5}$
    匹配不是a-z的任意字符串:[^a-z]
    匹配有字符串0-1个数字、字母或者下划线:^[0-9a-zA-Z_]?$ ^\w?$
    字符串有一个或多个空白符号(\t\n\r等): ^\s+$ ^\s{1,}$
    字符串有0个或若干个任意字符(除了\n):^.{,}$  ^.*$
    匹配0或任意多组ABC:^(ABC)*$
    字符串要么是ABC,要么是123:^ABC$|^123$ ^(ABC|123)$
    字符串只有一个点号:^[.]$
    匹配十进制3位数字:^[1-9][0-9]{2}$
    匹配0-999的数字:^([0-9]|[1-9][0-9]{1,2})$
    匹配0-255的数字:^([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    C语言中的正则匹配

    #include
    int regcomp(regex_t *preg, const char *pattern, int cflags)
        编译正则表达式
        preg:指向regex_t结构体的指针,用于存储编译后的正则表达式。
    	pattern:要编译的正则表达式字符串。
    	cflags:编译选项,可以使用以下常量按位或操作组合:
            REG_EXTENDED:支持扩展正则表达式语法。
            REG_ICASE:忽略大小写。
            REG_NOSUB:不存储匹配的子字符串。
            REG_NEWLINE:将'.'视为匹配任何字符,包括换行符。
    int regexec(const regex_t *preg, const char *string, size_t nmatch, 
                regmatch_t pmatch[], int eflags)
       	进行模式匹配
        preg:指向编译后的正则表达式的regex_t结构体指针。
    	string:要匹配的字符串。
    	nmatch:regmatch_t结构体数组的大小,表示最多可以存储的匹配结果数量。
    	pmatch:存储匹配结果的regmatch_t结构体数组。
    	eflags:匹配选项,可以使用以下常量按位或操作组合:
            REG_NOTBOL:不将字符串的开头视为行的开头。
            REG_NOTEOL:不将字符串的结尾视为行的结尾。
            REG_EXTENDED:使用扩展正则表达式语法。
    void regfree(regex_t *preg)
        当不再需要编译的正则表达式时要将其释放
        preg:指向编译后的正则表达式的regex_t结构体指针。
    size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
        errcode:错误码,通常是regcomp()regexec()的返回值。
    	preg:指向编译后的正则表达式的regex_t结构体指针。
    	errbuf:存储错误信息的缓冲区。
    	errbuf_size:缓冲区的大小。
        
    #include 
    #include 
    #include 
    
    int main(int argc, char** argv)
    {
        if(argc != 3)
        {
            printf("Uasge: %s RegexString Text \n", argv[0]);
            return 1;
        }
    
        const char* pregexstr = argv[1]; // 正则的输入
        const char* ptext = argv[2]; // 要匹配的文本
        regex_t oregex; // 声明正则结构体
        int nerrcode = 0;
        char szerrmsg[1024] = {0};
        size_t unerrmsglen = 0;
        // 编译正则表达式
        if((nerrcode = regcomp(&oregex, pregexstr, REG_EXTENDED|REG_NOSUB)) == 0)
        {
            if((nerrcode = regexec(&oregex, ptext, 0, NULL, 0)) == 0)
            {
                // 匹配成功
                printf("%s matches %s\n", ptext, pregexstr);
                regfree(&oregex);
                return 0;
            }
        }
    	// 匹配失败
        unerrmsglen = regerror(nerrcode, &oregex, szerrmsg, sizeof(szerrmsg));
        unerrmsglen = unerrmsglen < sizeof(szerrmsg) ? unerrmsglen : sizeof(szerrmsg) - 1;
        szerrmsg[unerrmsglen] = '\0';
        printf("ErrMag: %s\n", szerrmsg);
        regfree(&oregex);
    
        return 0;
    }
    
    ./a.out "^[0-9]{3}$" 123  // 输出 123 matches ^[0-9]{3}$
    
    • 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

    常用命令

    sort命令

    命令从标准输入中读取数据然后按照字符串内容进行排序

    -f 忽略字符大小写
    -n 比较数值的大小
    -t 指定分割符,默认是空格或者tab
    -k 指定分割后进行比较字段
    -u 重复的行只显示一次
    -r 反向排序
    -R 打乱排序,同样的行洗不乱
    
    cat test.txt | sort -u -k2 -n # 分割后按照数值比较第二列,不重复显示
    cat /etc/passwd | sort -t: -k3 -n -u # 给 /etc/passwd 使用用户id排序
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    uniq

    去除重复的行,前提是重复的行连续

    -c 显示每行重复的次数
    -d 仅显示重复过的行
    -u 仅显示不曾重复的行
    sort < test.txt | uniq
    cat test.txt | sort | uniq
    
    • 1
    • 2
    • 3
    • 4
    • 5

    wc

    word count 统计数量

    -l 统计行数
    -c 统计字节数
    -w 统计单词数
    不加选项,那么就会依次输出行数、单词数、字节数
    cat /etc/passwd | wc -l
    
    • 1
    • 2
    • 3
    • 4
    • 5

    grep

    是一种文本搜索工具,可以使用正则表达式搜索文本,并把匹配的行打印出来。grep家族包含grepegrepfgrepegrepgrep的扩展,支持更多的re元字符,fgrepfixed grep,把所有的字母看作是单词,正则表达式中的元字符表示其自身的字面意义,不在特殊。LinuxGNU版本的grep,功能更加的强大,通过选项 -G-E-F来使用egrepfgrepgrep默认使用的基本的正则。

    egrep = grep -E # 扩展正则
    fgrep = grep -F
    rgrep = grep -r
    grep [options]
    -c 只输出匹配行的计数
    -i 不区分大小写
    -h 查询多文件时,不显示文件名
    -H 查询多文件时,显示文件名
    -l 查询多文件时,只输出包含匹配字符的文件名
    -L 列出不匹配的文件名
    -n 显示匹配行以及行号
    -w 只匹配整个单词,而不是字符串的一部分,例如匹配magic 那么magical就不行
    -s 不显示不存在或无匹配文本的错误信息
    -v 显示不包含匹配文本的所有行
    -r 递归搜索某个目录下的所有文件
    -F 不使用正则,使用固定字符串作为匹配
    -P 使用perl正则
    -E 使用扩展正则
    --color=auto 可以将找到的关键字部分加上颜色显示
    grep -P "\d\d" test.txt
    grep -F "#include" *.c -n -H -w
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    find

    find pathname -options [-print -exec -ok ...]
    # 命令参数
    -print find命令所查找的目录路径。例如用.表示当前目录,用/表示系统根目录,递归查找
    -exec 对匹配的文件执行该参数所给出的shell命令,相应的命令的形式为'command' {} \; ,
    	注意{}内部无空格,和\;之间有一个空格。
    	find . -type f -exec ls -l {} \; # 每找到一个文件,就会执行exec后面的命令
    	find . -name "*.txt" -exec cp {} ./gz/ \;
    -ok 和-exec的作用相同,更加安全,在执行每一个命令之前,给出提示,输入y才会执行后面的语句。
    	find . -name "*.txt" -ok ls -l {} \;
    # options 命令选项
    -name 按照文件名查找文件 find .  -name "06*"
    -perm 按照文件权限来查找文件 find . -perm 0064
    -prune 可以使得find命令不在当前指定目录中查找,同时使用-depth,那么将被忽略
    -user 按照文件属主来查找文件 find . -user root
    -group 按照文件所属组来查找文件
    -mtime -n/+n 按照文件的更改时间来查找文件,
    		-n 表示文件更改时间距现在n天以内,+n 表示文件更改时间距现在n天以前
    		find . -mtime -2
    -atime 和mtine类似,访问时间
    -ctime 和mtime类似,创建时间
    -nogroup 查找无有效所属组的文件,该文件所属组在/etc/groups中不存在 find ./ -nogroup
    -nouser 查找无有效属主的文件,该文件属主在/etc/passwd中不存在 find ./ -nouser
    -newer file1 ! file2 查找更改时间比文件file1新但比文件file2旧的文件
    -type 查找某一类型的文件
    	b 块设备 d 目录 c 字符设备 p 管道文件 l 符号链接文件 f 普通文件
    -maxdepth find递归的最大深度
    -mindepth find递归的最小深度
    -depth find递归的深度
    -szie n 查找文件长度为n块的文件 find ./ -size 7c
    -fstype 查找某一类型文件系统中的文件
    -mount 在查找文件时不跨越文件系统mount点
    -follow 遇到符号链接文件跟踪至链接所指向的文件
    
    • 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

    xargs

    将标准输入的参数整齐的拼凑在一行里边。一般需要配合其他命令使用

    cat test.txt | xargs touch
    # 加入test.txt内容
    a
    b
    c
    # 上面的命令解释为 touch a b c, 即将cat test.txt | xargs产生的全部内容放到最后面
    find . -name "*.sh" | xargs mv -I{} mv {} ./test
    # 其中的-I{} 表示使用{}来表示find . -name "*.sh" | xargs产生的全部内容,假设为a
    # 那么就相当于 mv a ./test
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    sed

    sed意为流处理器,将前一个程序的输出引入sed的输入,经过一系列的编辑命令转换为另一种格式输出。文本1 -> sed + 脚本 -> 文本2。sed以行为单位处理文件。

    sed option 'script' file1 file2 .... 
    sed option -f scriptfile file1 file2 ....
    sed '/pattern/actions' file1 file2 ... # pattern正则表达式 actions匹配成功后的动作
    sed -n '2p' test.txt # 输出 test.txt 的第二行
    sed '2d' test.txt # 删除第二行 
    sed '$d' test.txt # 删除最后一行 
    sed '2,5d' test.txt # 显示删除2到5行的结果
    sed '/12/d' test.txt # 匹配到12就删除该行,显示其他结果
    # p(print)打印 i(inserd)插入 a(append)追加 d(delete)删除 s(substition)替换
    sed '2i aasscc' test.txt # 在第二行插入 aasscc
    sed 's/123/567/' test.txt # 将文本中的123替换为567
    sed -n test.txt # 静默输出
    -e 允许多个脚本指令被执行
    -i 直接修改源文件
    -r 在脚本指令中使用扩展正则表达式
    -s 将指定的多个文件允许把他们当作单独的文件,正则表达式则不进行跨文件匹配
    -u 最低限度的缓存输入输出
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    awk

    不仅能以行为单位还能以列为单位处理文件。awk缺省的行分隔符是换行,缺省的列分隔符是连续空格或者tab。但是行分隔符和列分隔符都可以自己定义。

    awk option 'script' file1 file2 ....
    awk option -f scriptfile file1 file2 ....
    /pattern/{actions} # 满足pattern正则执行actions
    condition/{actions} # 满足condition条件执行actions
    {actions} # 对每一行都进行处理执行actions
    BEGIN {action} # 在遍历文本第一行之前执行某个动作
    END {action} # 在遍历完文本执行某个动作
    
    cat /etc/passwd | awk -F: '{print $3}' # -F:分隔符为: 打印第三列 $0表示当前行
    awk '{print $1}' test.txt # 打印第一列
    awk '/^Pro/{print $2}' test.txt # 开头匹配到Pro的行打印第二列
    # 第二列小于75打印当前行和REORDER,大于等于的打印当前行
    awk '$2<75 {printf "%s\t%s\n", $0, "REORDER";} $2>=75 {printf "%s\n", $0;}' test.txt
    BEGIN{
    	printf "%s\t%s\n", "产品", "库存";
    	sum=0;
    }
    {
    	printf "%s\t%s" ,$1 ,$2;
    	sum+=$2;
    }
    END{
    	printf "库存总量:%d\n", sum;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    crontab

    linux 系统定时器

    # Example of job definition:
    # .---------------- minute (0 - 59)
    # |  .------------- hour (0 - 23)
    # |  |  .---------- day of month (1 - 31)
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
    # |  |  |  |  |
    # *  *  *  *  * user-name command to be executed
    17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
    	每小时的第17分钟,root去执行后面的指令
    25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily ) 
    	每天的凌晨6点25分的时候,root去执行后面的指令
    47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
    	每周的星期天的6点47,root去执行后面的指令
    52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
    	每月中的第一天的6点52,root去执行后面的指令
    
    # 先执行crontab –e在添加,或者直接vim /etc/crontab
    crontab –e : 修改 crontab 文件. 如果文件不存在会自动创建。
    crontab –l : 显示 crontab 文件。
    crontab -r : 删除 crontab 文件。
    crontab -ir : 删除 crontab 文件前提醒用户。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    VScode运行C/C++
    【校招VIP】前端JS语言考点之px rem等单位
    手把手教你使用Python写贪吃蛇游戏(pygame)
    FOTS:端到端的文本检测与识别方法的原理应用与优势
    springboot个性化课程推荐系统毕业设计源码131805
    学习、实习、校招
    MySQL8.0.28安装教程
    向量数据库入坑:传统文本检索方式的降维打击,使用 Faiss 实现向量语义检索
    Redis_Hash(Map)数据类型基本命令
    Linux常用命令
  • 原文地址:https://blog.csdn.net/weixin_45205160/article/details/132686970