Loading

Linux Shell脚本

Linux Shell脚本

变量

声明变量

name="zhangsan"    

注意:等号两侧不能有空格

变量命名规则:

  • 只包含字母、数字和下划线
  • 不能以数字开头
  • 避免使用 Shell 关键字
  • 大写字母表示常量

引用变量

变量名前加$符号为引用变量

echo $name
echo ${name}

只读变量

name="zhangsan"
readonly name

删除变量

name="zhangsan"
unset name

声明命令执行结果

# 使用`xxx`
PWD_PATH=`pwd`
# 使用$(xxx)
PWD_PATH=$(pwd)

变量类型

字符串类型

单引号字符串

name='zhangsan'

# 单引号内变量无效
hello_name_2='hello $name'

# 单引号拼接字符串
hello_name='hello'$name' ! '

单引号字符串的限制:

  • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
  • 单引号字符串中不能出现单独一个的单引号(对单引号使用转义符也不行),但可成对出现,作为字符串拼接使用。

双引号字符串

name="zhangsan"

# 双引号内可以使用变量
hello_name="hello $name"

# 双引号转义
hello_name="hello  \"$name\" !"

双引号的优点:

  • 双引号里可以有变量
  • 双引号里可以出现转义字符

字符串拼接

name="zhangsan"

# 使用${}直接拼接字符串
echo ${name}123

# 双引号字符串拼接
echo "my name is $name, ok!"
echo "my name is "${name}", ok!"

# 单引号字符串拼接
echo 'my name is'$name',ok!'

字符串长度

name="zhangsan"
echo ${#name}

字符串截取

根据下标截取

格式:${string: start :length}

string:表示源字符串

start:截取字符串的起始位置,注意第一个字符下标为0

length:截取字符串的长度

str="my name is zhangsan"

# 第1个字符开始截取2个字符,输出"my"
substr=${str:0:2} 

根据字符截取
  • 使用 # 截取匹配字符后右侧的内容

    格式:${string#*chars} 从左往右匹配,命中第一个匹配字符,剩下右侧字符串

    格式:${string#*chars} 从左往右匹配, 命中最后一个匹配字符,剩下右侧字符串

  • 使用 % 截取匹配字符后左侧的内容

    格式:${string%chars*} 从右往左匹配,命中第一个匹配字符,剩下左侧字符串

    格式:${string%chars*} 从右往左匹配,命中最后一个匹配字符,剩下左侧字符串

PWD_PATH="/var/run/gitlab/puma"
# 获取目录的文件名
echo ${PWD_PATH##*/}

# 获取父目录
echo ${PWD_PATH%/*}

字符串替换

格式:${string/old/new}

string:源字符串

old:源字符串中要被替换的内容

new:新字符串

file_name="package.tgz"
echo ${file_name/tgz/zip}

数字类型

声明

total=5

计算

shell
a=10
b=20

# 中括号内必须有空格,不能与表达式相连
c=$[ $a + $b ]

# 双括号允许在比较语句中使用高级数学表达式,也可以与美元符号搭配,用于整型数据计算
d=$(($a + $b + $c))

双括号支持的运算符:

运算符 含义
val++ 后增
val-- 后减
++val 先增
--val 先减
逻辑求反
按位求反
** 幂运算
<< 左移位
>> 右移位
& 布尔与
| 布尔或
&& 逻辑与
|| 逻辑或
expr
a=10
b=20

val=`expr $a + $b`
echo "a + b : $val"

val=`expr $a - $b`
echo "a - b : $val"

val=`expr $a \* $b`
echo "a * b : $val"

val=`expr $b / $a`
echo "b / a : $val"

val=`expr $b % $a`
echo "b % a : $val"
let
a=10
b=20
let a=a+b
echo $a
let a++
echo $a

数组类型

初始化

arr=(1 'nice' '2days')

# 凡是以空格分割的数据即可作为数组
# 例如:ls 的输出结果即为数组
for name in `ls`;do
    echo $name
done
# 例如:将','替换为' '形成数组
for name in `echo "a,b,c" | sed '/,/ /g'`;do
    echo $name
done

输出

echo ${arr[*]}  

# '*'可以使用'@'代替
echo ${arr[@]}

新增、修改元素

arr[0]='yum'

数组长度

echo ${#arr[*]}

索引元素

索引下标0位第一个元素

echo ${arr[0]}

遍历数组

for e in ${arr[*]};do
    echo $e
done

字典类型

声明变量

declare -A id_name_map

初始化

id_name_map=(["1001"]="tom" ["1002"]="jery")

输出

# 输出所有key
echo ${!id_name_map[*]}
# 输出所有value
echo ${id_name_map[*]}

# '*'可以使用'@'代替
echo ${!id_name_map[@]}
echo ${id_name_map[@]}

新增、修改

id_name_map["1003"]="sunny"
id_name_map["1001"]="zhang"

字典长度

echo ${#id_name_map[*]}

遍历字典

for key in ${!id_name_map[*]};do
    echo ${id_name_map[$key]}
done

运算符

运算符表达式

name="zhangsan"
age=10

# 字符串变量比较相同
[ "$name" = "zhangsan" ]

# 数字变量比较相同
[ $age -eq 5 ]

# 数字变量转换为字符串变量
[ "$age" = "10" ]

注意:

  • **中括号内的表达式两侧必须有空格 **
  • **字符串比较时,变量最好使用双引号转义,部分Linux系统的shell会报错:过多的参数 **

字符串运算符

运算符 说明 举例
= 检测两个字符串是否相等,相等返回 true。 [ $a = $b ] 返回 false。
!= 检测两个字符串是否不相等,不相等返回 true。 [ $a != $b ] 返回 true。
-z 检测字符串长度是否为0,为0返回 true。 [ -z $a ] 返回 false。
-n 检测字符串长度是否不为 0,不为 0 返回 true。 [ -n "$a" ] 返回 true。
$ 检测字符串是否不为空,不为空返回 true。 [ $a ] 返回 true。

示例:

a="abc"
b="efg"

if [ $a = $b ];then
   echo "$a = $b : a 等于 b"
else
   echo "$a = $b: a 不等于 b"
fi

if [ $a != $b ];then
   echo "$a != $b : a 不等于 b"
else
   echo "$a != $b: a 等于 b"
fi

if [ -z $a ];then
   echo "-z $a : 字符串长度为 0"
else
   echo "-z $a : 字符串长度不为 0"
fi

if [ -n "$a" ];then
   echo "-n $a : 字符串长度不为 0"
else
   echo "-n $a : 字符串长度为 0"
fi

if [ $a ];then
   echo "$a : 字符串不为空"
else
   echo "$a : 字符串为空"
fi

数字运算符

运算符 说明 举例
-eq 检测两个数是否相等,相等返回 true。 [ $a -eq $b ] 返回 false。
-ne 检测两个数是否不相等,不相等返回 true。 [ $a -ne $b ] 返回 true。
-gt 检测左边的数是否大于右边的,如果是,则返回 true。 [ $a -gt $b ] 返回 false。
-lt 检测左边的数是否小于右边的,如果是,则返回 true。 [ $a -lt $b ] 返回 true。
-ge 检测左边的数是否大于等于右边的,如果是,则返回 true。 [ $a -ge $b ] 返回 false。
-le 检测左边的数是否小于等于右边的,如果是,则返回 true。 [ $a -le $b ] 返回 true。

示例:

a=10
b=20

if [ $a -eq $b ];then
   echo "$a -eq $b : a 等于 b"
else
   echo "$a -eq $b: a 不等于 b"
fi

if [ $a -ne $b ];then
   echo "$a -ne $b: a 不等于 b"
else
   echo "$a -ne $b : a 等于 b"
fi

if [ $a -gt $b ];then
   echo "$a -gt $b: a 大于 b"
else
   echo "$a -gt $b: a 不大于 b"
fi

if [ $a -lt $b ];then
   echo "$a -lt $b: a 小于 b"
else
   echo "$a -lt $b: a 不小于 b"
fi

if [ $a -ge $b ];then
   echo "$a -ge $b: a 大于或等于 b"
else
   echo "$a -ge $b: a 小于 b"
fi

if [ $a -le $b ];then
   echo "$a -le $b: a 小于或等于 b"
else
   echo "$a -le $b: a 大于 b"
fi

文件与目录运算符

用于判断文件或目录是否存在、是否具有相关权限等

操作符 说明
-s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。
-f file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。
-d file 检测文件是否是目录,如果是,则返回 true。
-e file 检测文件(包括目录)是否存在,如果是,则返回 true。
-c file 检测文件是否是字符设备文件,如果是,则返回 true。
-b file 检测文件是否是块设备文件,如果是,则返回 true。
-S file 检测文件是否为socket类型
-L file 检测文件是否为符号链接
-p file 检测文件是否是有名管道,如果是,则返回 true。
-g file 检测文件是否设置了 SGID 位,如果是,则返回 true。
-u file 检测文件是否设置了 SUID 位,如果是,则返回 true。
-r file 检测文件是否可读,如果是,则返回 true。
-w file 检测文件是否可写,如果是,则返回 true。
-x file 检测文件是否可执行,如果是,则返回 true。

示例:

data_path=/data
properties_file=$data_path/cupid/application.properties

if [ -d $data_path ];then
    if [ -f $properties_file ];then
        cat $properties_file
    else
        echo "$properties_file not exit !"
    fi
else
    echo "$data_path not exit !"
fi

逻辑运算符

[ ] 逻辑运算符

运算符 说明 举例
! 非运算,表达式为 true 则返回 false,否则返回 true。 [ ! false ] 返回 true。
-o 或运算,有一个表达式为 true 则返回 true。 [ $a -lt 20 -o $b -gt 100 ] 返回 true。
-a 与运算,两个表达式都为 true 才返回 true。 [ $a -lt 20 -a $b -gt 100 ] 返回 false。

[[ ]] 逻辑运算符

运算符 说明 举例
&& 逻辑的 AND [[ $a -lt 100 && $b -gt 100 ]] 返回 false
|| 逻辑的 OR [[ $a -lt 100 || $b -gt 100 ]] 返回 true

参数传递

shell脚本执行时,可携带参数传入脚本中

#!/bin/bash

# shell文件路径
echo $0

# 第一个参数
echo $1

# 第二个参数
echo $2

参数说明:

参数 说明
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数。 如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。 如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$- 显示Shell使用的当前选项,与set命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。shell脚本中exit语句的返回值

流程控制

if

示例:

name="zhang"

if [ "$name" = "zhang" ];then
    echo "1"
elif [ "$name" = "wang" ];then
    echo "2"
else
    echo "none"
fi

if的判断语句有多种:

[ 表达式 ]

单中括号中,表达式两侧应有空格,且表达式逻辑运算符使用"-a"、"-o"、"!"

[[ 表达式 ]]

双中括号中,表达式两侧应有空格,且表达式逻辑运算符使用"&&","||"

(( ... ))

双括号中,表达式可以使用">"、"<"、"=="等运算符

for

# 循环目录下的文件
for file in `ls /data`;do
    echo "file name is $file"
done

# 循环1至10
for i in `seq 1 10`;do
    echo $i
done

while

count=0
while true;do
    if [ $count -eq 5 ];then
        continue
    fi
    if [ $count -ge 10 ];then
        break
    fi
    echo $count
done

函数

# 定义方法,返回值必须是整数,取值范围(0-255)
function add() {
    a=$1
    b=$2
    return $(($a + $b))
}

# 执行方法,参数传递
add 1 2

# 获取返回值
echo $?

文件包含

shell可以将其他脚本声明的变量等导入当前脚本

. filename   # 注意点号(.)和文件名中间有一空格

或

source filename

Linux 命令

seq

Linux seq 命令用以指定增量从首数开始打印数字到尾数。

seq [选项]... 尾数
seq [选项]... 首数 尾数
seq [选项]... 首数 增量 尾数

**参数说明: **

  • -f, --format=格式 使用printf 样式的浮点格式
  • -s, --separator=字符串使用指定字符串分隔数字(默认使用:\n)
  • -w, --equal-width 在列前添加0 使得宽度相同

tr

语法说明

Linux tr 命令用于转换或删除文件中的字符。

tr 指令从标准输入设备读取数据,经过字符串转译后,将结果输出到标准输出设备。

tr [OPTION]… SET1 [SET2]

参数说明:

  • -c, --complement:反选设定字符。也就是符合 SET1 的部份不做处理,不符合的剩余部份才进行转换
  • -d, --delete:删除指令字符
  • -s, --squeeze-repeats:缩减连续重复的字符成指定的单个字符
  • -t, --truncate-set1:削减 SET1 指定范围,使之与 SET2 设定长度相等

字符集合的范围:

  • \\ 反斜杠
  • \b Ctrl-H 退格符
  • \f Ctrl-L 走行换页
  • \n Ctrl-J 新行
  • \r Ctrl-M 回车
  • \t Ctrl-I tab键
  • \v Ctrl-X 水平制表符
  • CHAR1-CHAR2 :字符范围从 CHAR1 到 CHAR2 的指定,范围的指定以 ASCII 码的次序为基础,只能由小到大,不能由大到小,例如:a-z、A-Z。
  • [CHAR*] :这是 SET2 专用的设定,功能是重复指定的字符到与 SET1 相同长度为止
  • [CHAR*REPEAT] :这也是 SET2 专用的设定,功能是重复指定的字符到设定的 REPEAT 次数为止(REPEAT 的数字采 8 进位制计算,以 0 为开始)
  • [:digit:] :所有数字
  • [:alpha:] : 所有字母字符
  • [:alnum:] :所有字母字符与数字
  • [:lower:] : 所有小写字母
  • [:upper:] : 所有大写字母
  • [:punct:] : 所有标点字符
  • [:blank:] : 所有水平空格
  • [:cntrl:] : 所有控制字符
  • [:graph:] : 所有可打印的字符(不包含空格符)
  • [:print:] : 所有可打印的字符(包含空格符)
  • [:space:] : 所有水平与垂直空格符
  • [:xdigit:] : 所有16 进位制的数字
  • [=CHAR=] : 所有符合指定的字符(等号里的 CHAR,代表你可自订的字符)

替换

小写转换为大写

echo "abcDEFG" | tr a-z A-Z
echo "abcDEFG" | tr [:lower:] [:upper:] 

tab替换为四个空格

echo "	123" | tr  \t  '    '

删除

删除小写字符

echo "abcDEFG" | tr -d a-z

grep

语法说明

grep命令主要用于文本过滤,查询出需要的行

grep [OPTION]... PATTERN [FILE]...

模式选择:
  -E, --extended-regexp     扩展正则表达式匹配
  -F, --fixed-strings       固定字符串匹配
  -G, --basic-regexp        基础正则表达式(默认)
  -P, --perl-regexp         Perl语言正则表达式匹配
  -e, --regexp=PATTERN      使用指定的PATTERN进行匹配(用于多个匹配条件)
  -f, --file=FILE           从文件中读取匹配内容
  -i, --ignore-case         忽略大小写
  -w, --word-regexp         强制匹配整个单词
  -x, --line-regexp         强制匹配整行
  -z, --null-data           以0字节作为换行判断依据

杂项:
  -s, --no-messages         阻止异常输出
  -v, --invert-match        反选

输出控制:
  -m, --max-count=NUM       匹配NUM行后停止
  -b, --byte-offset         打印命中字符的在当前行的字节偏移量
  -n, --line-number         打印命中行的行号
      --line-buffered       每行刷新输出
  -H, --with-filename       打印文件名
  -h, --no-filename         阻止打印文件名
      --label=LABEL         使用LABLE作为文件名
  -o, --only-matching       只显示匹配的内容
  -q, --quiet, --silent     阻止所有输出
      --binary-files=TYPE   假定文件类型为binary;
                            TYPE包括:'binary', 'text','without-match'
  -a, --text                假定文件类型为text
  -I                        equivalent to --binary-files=without-match
  -d, --directories=ACTION  如何处理目录;
                            ACTION包括:'read', 'recurse', or 'skip'
  -D, --devices=ACTION      如何处理devices, FIFOs and sockets;
                            ACTION包括:'read' or 'skip'
  -r, --recursive           like --directories=recurse(递归)
  -R, --dereference-recursive  likewise, but follow all symlinks
      --include=FILE_PATTERN  search only files that match FILE_PATTERN
      --exclude=FILE_PATTERN  skip files and directories matching FILE_PATTERN
      --exclude-from=FILE   skip files matching any file pattern from FILE
      --exclude-dir=PATTERN  directories that match PATTERN will be skipped.
  -L, --files-without-match  没有选中的行只打印文件名
  -l, --files-with-matches  选中的行只打印文件名
  -c, --count               仅打印匹配的行数
  -T, --initial-tab         打印列对齐
  -Z, --null                打印文件名之后追加0字节

上下文控制:
  -B, --before-context=NUM  打印匹配行之前的NUM行
  -A, --after-context=NUM   打印匹配行之后的NUM行
  -C, --context=NUM         打印匹配行之前和之后的NUM行
  -NUM                      类似 --context=NUM
      --color[=WHEN],
      --colour[=WHEN]       匹配的内容进行标记并高亮显示;
                            WHEN包括:'always', 'never', or 'auto'
  -U, --binary              EOL不去掉CR字符 (MSDOS/Windows)

正则表达式

符号 含义
c 匹配字符
\c 匹配转义后的字符c
. 匹配一个非换行符的字符
^ 锚定行的开始
$ 锚定行的结束
[abc...] 匹配一个指定范围内的字符,如[Gg]rep匹配Grep和grep
[^abc...] 匹配一个不在指定范围内的字符,如:[^A-FH-Z]rep,不以A-F和H-Z开头且紧跟rep
r1|r2 匹配条件 r1 或 r2
r1r2 匹配条件 r1 和 r2
r? 匹配0次或一次
r+ 匹配一次以上
r* 匹配任意次
(r) 匹配组
r 匹配n次
r 匹配n次以上
r 匹配n至m次
\< 匹配单词左边界
\> 匹配单词右边界
\s 匹配任意空白字符
\S 匹配任意非空白字符
\w 匹配单词组成字符(大小写字母、数字、下划线)
\W 匹配非单词组成字符
\y 匹配单词左右边界部分的空字符位置 "hello world"
\B 和\y相反,匹配单词内部的空字符位置,例如"crate" ~ /c\Brat\Be/成功
\` 匹配字符串的绝对行首 "abc\ndef"
\' 匹配字符串的绝对行尾

示例:

# 过滤出包含Excepiton的行,并打印其之前的5行和之后的20行
grep -B 5 -A 20 'Exception'  /data/cupid/webserver/logs/sajjm-error.log

# 统计日志中Exception出现的次数
grep -c Exception /data/cupid/webserver/logs/sajjm-error.log

# 过滤出包含kafka的进程,且过滤掉执行grep命令的进程
ps -ef |grep kafka | grep -v grep

# 多个匹配条件,过滤出包含‘Exception’或'com.venus'的行
grep -e 'Exception' -e 'com.venus' /data/cupid/webserver/logs/sajjm-error.log

sed

语法说明

sed命令主要用于文本的替换和修改

语法:

  • sed [选项] 'sed编辑命令' 输入文件
  • shell 命令 | sed [选项] 'sed编辑命令'
  • sed [选项] -f sed脚本文件 输入文件

选项:

  • -n:只显示匹配处理的行(否则会输出所有)
  • -e:执行多个编辑命令时(一般用 ; 代替)
  • -i:直接在文件中进行修改,而不是输出到屏幕
  • -r:支持扩展正则表达式
  • -f:从脚本文件中读取内容并执行(文件中的编辑命令每行一个,不用;隔开)

编辑命令:

  • p:打印匹配行 print
  • a:在匹配行后面追加 append
  • i:在匹配行前面插入 insert
  • c:整行替换
  • s:字符串替换(匹配正则表达式)substitution
  • d:删除指定行 delete
  • r:将文件的内容读入 read
  • w:将文本写入文件 write
  • =:输出行号

检索匹配方式:

  • 行号匹配
  • 模式匹配(正则表达式=字符+特殊符号)

行号匹配

匹配格式:sed -n '行号1,行号2命令' 输入文件

# 输出第一行
sed -n '1p' /etc/passwd
# 输出最后一行
sed -n '$p' /etc/passwd
# 输出一到五行
sed -n '1,5p' /etc/passwd
# '+'设置行数,输出第四行及其后面五行
sed -n '4,+5p' /etc/passwd
# '~'设置步长值,输出单数行,步长为2
cat -n /etc/passwd | sed -n '1~2p'
# '!'匹配取反,4到最后一行不显示
sed -n '4,$!p' /etc/passwd
# 多个命令用';'分割,输出1行,3至5行,7行及之后的2行
sed -n '1p;3,5p;7,+2p' /etc/passwd

模式匹配

匹配格式:sed -n '/模式/命令' 输入文件

# 输出有root的行
sed -n '/root/p' /etc/passwd
# 以#或者$开头的行不显示
cat /etc/ssh/sshd_config |sed -rn '/^#|^$/!p'
# 显示以/结尾的行,需要转义
df -Th| sed -n '/\/$/p'

p:打印命令

# 输出第一行和包含data字符串的行
sed -n '1p;/data/p' rc.local

a:追加命令

格式:sed -i '匹配模式a 追加内容' 输入文件

# 第一行后增加一行,内容为:abc
sed -i '1a abc' rc.local
# 所有包含'/data'的行后追加一行,内容为:abc
sed -i '/\/data/a abc' rc.local

i: 插入命令

# 第一行前增加一行,内容为:abc
sed -i '1i abc' rc.local
# 所有包含'/data'的行前追加一行,内容为:abc
sed -i '/\/data/i abc' rc.local

d:删除命令

# 以正则表达式匹配删除,内容为abc的行被删除
sed -ri '/^abc$/d' rc.local
# 通配符匹配删除
sed -i '/xda-web.stub/d' /etc/rc.local
# '/'需要转义
sed -i '/(\/data\/cupid\/xda-web.stub &)/d' /etc/rc.local

c:整行替换命令

# 将第一行替换为#/bin/bash
sed -i '1c #/bin/bash' /etc/rc.ocal
# 将包含data字符串的行替换为123
sed -i '/data/c 123' /etc/rc.local

s:字符串替换命令

sed -i '[行号或模式]s/查找内容/替换内容/[替换标记]' 输入文件

替换标记:

  • 数字:替换每行的第几个
  • g:全局替换,否则只替换第一个字符串。例如ng从第n个开始替换
  • p:显示被执行替换操作的行,和-n合用
  • w:将执行替换操作的行输出到指定文件
# 第11行的10替换为20
sed -i '11 s/10/20/' rc.local

# 将','替换为空格,从而转换成数组
echo "apple,pen,orange" | sed  's/,/ /g'

# 将内容包含'/data'的行的'cupid'全部替换为'xda-web'
sed -i '/\/data/ s/cupid/xda-web/g'  /etc/rc.local

# 支持\r、\n、\t的替换,将所有\t转换为四个空格
sed -i 's/\t/    /g' /etc/rc.local

s命令可以使用任意分隔符作为定界符(即转义字符)

# 当替换路径时'/'作为定界符需要频繁转义,可以使用其他定界符,s后的第一个字符为定界符,此处示例使用#为定界符
# 将'/data/cupid'替换为'/data/xda-web/'
sed -i 's#/data/cupid#/data/xda-web/g' /etc/rc.local

多条s命令的执行

  • 使用 -e 选项
  • 使用 ; 分割
# -e 选择
sed -e 's/feng/fdy/' -e '/lxf/ s/500/200/' ip.txt
 
# ;分割命令
sed 's/feng/fdy/; /lxf/ s/500/200/' ip.txt

# {;}分割命令
sed '{s/feng/fdy/; /lxf/ s/500/200/}' ip.txt

&:模糊匹配内容修改

# 将fat和cat增加双引号

# 错误命令
echo "fat and cat" | sed 's/.at/".at"/g'

# 正确命令
echo "fat and cat" | sed 's/.at/"&"/g'

标签:正则表达式元组匹配修改

  • 标签:sed使用圆括号定义替换模式的部分字符
  • 标签可以方便在后面引用,每行指令最多使用9个标签
  • \1 代表第一个圆括号定义的内容,\2 代表第二个,以此类推
# 把后面 .* 部分删除
sed -r 's/(^[0-z]+)(.*)/\1/' /etc/passwd
 
# 把前面 ^[0-z]+ 部分删除
sed -r 's/(^[0-z]+)(.*)/\2/' /etc/passwd
 
# 倒序输出
echo aaa bbb ccc | sed -r 's/([a-z]+) ([a-z]+) ([a-z]+)/\3 \2 \1/'
ccc bbb aaa
 
# 其实有些操作awk更方便
echo aaa bbb ccc| awk '{print $3,$2,$1}'
ccc bbb aaa

引用shell变量

# 双引号内引用shell变量
sed -i "/my is $name/d" /etc/rc.local

# 单引号外拼接引用shell变量
sed -i 'my is '$name'/d' /etc/rc.local

awk

语法说明

awk是一门模式扫描和处理的编程语言,主要用于文本截取和分析,支持流程控制和正则表达式,详细可参见

awk [ -- ] program-text file ...
awk -f program-file [ -- ] file ...
awk -e program-text [ -- ] file ...

常用格式

b16bd0a164578f2bc13ddb75c8a9ea53

awk -F '分隔符' '/模式/{动作}'  输入文件
  • 分隔符用于切分行字符串,可以使用正则表达式
  • 指令包括模式和动作,使用单引号引起,单引号内$不会被shell解析为变量
  • 模式可以使用正则表达式、条件表达式或两种组合
    • 正则表达式要用定界符 / 包裹
    • 条件表达式在下面单独说明
  • 动作必须使用大括号引起,多个动作之间用 ; 分开
  • 动作引用自定义变量,不需要接$符号

选项

  • -F fs 指定输入字段分隔符(FS预定义变量也可设置)
  • -v var=value 自定义变量,常用于引入shell中的变量
  • -n 识别文件输入中的8进制数(0开头)和16进制数(0x开头),例如:echo '030' | awk -n '{print $1+0}'
  • -f program-file 指定读取程序的文件名
  • -e program-text 指定awk程序表达式,可结合-f选项同时使用,在使用了-f选项后,如果不使用-e,awk program是不会执行的,它会被当作ARGV的一个参数
  • -o [filename] 格式化awk代码。不指定filename时,则默认保存到awkprof.out,指定为-时,表示输出到标准输出

简要执行流程

f671dccdfbbb514dd37af5da10b8e776

分隔符

分隔符用于切分输入和拼接输出

  • 输入分隔符
    • 行分隔符RS
    • 列分隔符FS、FIELDWIDTHS、FPAT
  • 输出分隔符
    • 行分隔符RT
    • 列分隔符OFS

RS

RS用于指定输入记录分隔符,RS通常设置在BEGIN代码块中,因为要先于读取文件就确定好RS分隔符,RS支持使用正则表达式分割记录。

  • RS="\n+" :默认匹配方式,按行读取,包含空行
  • RS="^$" : 一次性读取所有数据
  • RS="" :按段落读取

FS

FS以分隔符切分行,获取未匹配分隔符的内容构成字段,行字段以指定分隔符拼接时适合此分隔符。

分隔符支持正则表达式,分隔符包括输入分隔符FS、输出分隔符OFS,-F用于设置输入分隔符FS

  • 默认分隔符为空格或TAB
  • 默认设置的分隔符为输入分隔符
  • 输出分隔符需要显性设置
# 以':'拆分输入行,输出结果以空格拼接
awk -F ':' '{OFS=" "} /gitlab/{print $1,$2,$3}' /etc/passwd

FIELDWIDTHS

FIELDWIDTHS以字符宽度读取行构成字段,行内容以固定宽度打印时适合此分隔符

# a.txt
ID  name    gender  age  email          phone

1   Bob     male    28   abc@qq.com     18023394012

2   Alice   female  24   def@gmail.com  18084925203

3   Tony    male    21   aaa@163.com    17048792503

4   Kevin   male    21   bbb@189.com    17023929033

5   Alex    male    18   ccc@xyz.com    18185904230

6   Andy    female  22   ddd@139.com    18923902352

7   Jerry   female  25   exdsa@189.com  18785234906

8   Peter   male    20   bax@qq.com     17729348758

9   Steven  female  23   bc@sohu.com    15947893212

10  Bruce   female  27   bcbd@139.com   13942943905

# 以字符长度读取,第一个字段去读4个字符,第二个字段读取8个字符,以此类推
awk 'BEGIN{FIELDWIDTHS="4 8 8 5 15 11"} length($0) > 1 && strtonum($1) > 0 {printf "行字符长度:%d ID:%d 姓名:%s  性别:%s  年龄:%s  邮箱:%s  电话:%s\r\n", length($0),$1, $2, $3, $4, $5, $6}' a.txt

FPAT

FPAT是取得匹配的字符部分作为字段,当使用分隔符无法正确切分时,使用FPAT更合适

echo 'Robbins,Arnold,"1234 A Pretty Street, NE",MyTown,MyState,12345-6789,USA' |\
awk '
    BEGIN{FPAT="[^,]*|(\"[^\"]*\")"}
    {
        for (i=1;i<NF;i++){
            print "<"$i">"
        }
    }
'

指令

执行过程:

  • 执行begin的commands
  • 每行匹配pattern,命中的执行后面的commands,partten和command组成的部分可存在多个
  • 最后一下end的commands

模式(pattern)

模式用于过滤数据,模式匹配如下所示:

  • BEGIN
  • END
  • BEGINFILE
  • ENDFILE
  • /regular expression/
  • relational expression
  • pattern && pattern
  • pattern || pattern
  • pattern ? pattern : pattern
  • (pattern)
  • ! pattern
  • pattern1, pattern2

示例:

#开头和结尾增加打印输出
awk -F : 'BEGIN{print "-start-"} /bash/{print $1,$3} END{print "-end-"}' /etc/passwd

# 统计并打印行数
awk 'BEGIN{i=0}{i++}END{print i}' /etc/passwd
正则表达式

正则匹配模式与grep类似,用于过滤行

# 以root开头的行
awk -F : '/^root/{print $0}' /etc/passwd
条件表达式
  • 精确条件匹配模式: 使用比较运算符(==、>=等)进行过滤
# 过滤出切分后第一列为值为root的行
awk -F : '$1 == "root" {print NR,$0}' /etc/passwd
  • 模糊条件匹配模式:使用'~'运算符
  • \< 单词界定符,定义开头
  • \> 单词界定符,定义结尾
  • . 定义任意字符
# /etc/passwd用户名包含gitlab的行
awk -F : '$1 ~ /gitlab/ {print NR, $0}'  /etc/passwd

# /etc/passwd用户名以gitlab开头且以www结尾的行
awk -F ":" '$1 ~ /\<gitlab.*www\>/ {print $0}' /etc/passwd

# 所有TCP监听端口号
 netstat -antp | awk -F " +|:|::1|:::|/" '($1 == "tcp" || $1=="tcp6") && $8 == "LISTEN" {print $5}'

动作(action)

动作用于执行命令,动作内容使用大括号引起{ command },多个命令使用';'分割

# 打印/etc/passwd中用户名包含a的账号,且统计总数
awk -F: 'BEGIN{i=0} {if($1 ~/a/) {print $1;i++}} END{print "total="i}' /etc/passwd

编程语言

变量

变量声明

awk在command中声明变量,无需定义变量类型,引用变量是也无需使用$符号,与javascript语法类似。

内置变量
内置变量名 含义
ARGC arguments count :命令参数的总数
ARGIND index in ARGV of the current file:当前参数的序号
ARGV Array of command line arguments:包含命令参数的数组
BINMODE Binary mode for all file I/O:二进制模式读取文件
CONVFMT Conversion format for numbers:数字类型转换为字符串类型时的格式化字符串,默认为%.6g
ENVIRON 包含当前环境变量的数组,示例:ENVIRON["HOME"]
ERRNO 命令执行异常错误信息
FIELDWIDTHS A whitespace separated list of field widths:使用字符宽度进行分割字段,
FILENAME The name of the current input file:当前文件的文件名
FNR record number in the current input file:每个文件的行号计数器
FPAT A regular expression describing the contents of the fields in a record:
FS The input field separator:输入字段分隔符, 默认为空白字符,即-F参数所设
IGNORECASE Controls the case-sensitivity of all regular expression and string operations:控制所有正则模式匹配的大小写,IGNORECASE=0忽略大小写
NF Number of Field in the current input record:当前行的列字段数计数器
NR Number of Record:行数计数器,当多个文件时,为所有文件的行号计数器
OFMT Output format for numbers:输出数字格式化,默认为%.6g
OFS Output field separator:输出字段分隔符, 默认为一个空格
ORS Output record separator:输出行分隔符,默认为\n
PROCINFO
RS Input Record Separator:输入行分隔符。RS=""以段落分行;RS="^$"读取所有数据为一行;RS="\n+"按行读取,忽略空行;
RT Record Terminator:输出行分隔符,例如:awk 'BEGIN{RS=":"}{print $0,RT}' /etc/passwd
RSTART 内置函数match(s,r),匹配命中字符串在整个字符串中的起始位置
RLENGTH 内置函数match(s,r),匹配命中字符串的长度,例如:awk 'BEGIN{ match("abcde", "bcd"); print RSTART,RLENGTH}'
SUBSEP 复杂索引数组的分隔符,默认分隔符为八进制\034,例如:awk 'BEGIN{ SUBSEP="#"; arr[1,2]=10; print arr["1#2"] }'

示例:

# 显示行号、列数、第一列、最后一列
awk -F : '{print NR, NF, $1,$(NF-1)}' /etc/passwd

# 显示3-5行
awk -F : 'NR >=3 && NR <=5 {print NR,$0}' /etc/passwd

# 读取多个文件
awk -F ":" '{print "file_name="FILENAME, "NR="NR, "FNR="FNR,$0}' /etc/passwd  /etc/group

# ifconfig结果使用RS以段落分行,获取网卡名称
ifconfig  | awk -F " +|:" 'BEGIN{RS=""} {print NR, $1}'

# 循环打印每一个切分后的field
cat a.txt | awk -F " " '{ for(i=1;i<=NF;i++) { printf "第%d行 第%d列 值:%s\r\n", NR, i, $i; } }'
变量类型

变量类型主要包括数值字符串

类型转换
  • 隐式转换

    • 算术运算符计算后转换为数值类型,无效字符串将转换成0
    • 数值连接空字符串转换为字符串类型
    # 字符串转换为数字类型
    awk 'BEGIN{ n = "123" + 1; print n }'
    awk 'BEGIN{ print "abc" + 1 }'
    awk 'BEGIN{ print "123abc" + 1 }'
    
    # 数字转换为字符串类型
    awk 'BEGIN{ print 123"abc" }'
    
  • 显式转换

    • 数值 转 字符串: 使用CONVFMT或sprintf()函数,CONVFMT默认格式化时值保留6位小数

      # 使用CONVFMT
      awk 'BEGIN{a=123.4567;CONVFMT="%.2f";print a""}' #123.46
      
      # sprintf()函数
      awk 'BEGIN{a=123.4567;print sprintf("%.2f", a)}' #123.46
      
      # printf()函数
      awk 'BEGIN{a=123.4567;printf("%.2f",a)}'
      
    • 字符串 转 数值:strtonum()函数

      gawk 'BEGIN{a="123.4567";print strtonum(a)}'
      
变量打印
属性方法
    OFS 		输出格式的列分隔符,缺省是空格
    ORS			输出记录分隔符,输出时用指定符号代替换行符

print 函数
    print [item1,item2,...]
    
printf 函数
	printf [-v var] format [item1,item2,...]
	注意:
		printf输出需要指定换行符号,format的格式必须与后面item对应
		常见格式:
			%c		显示字符的ASCII码		
			%d|i 	显示十进制整数		
			%e|E	显示科学计数法数值	  
			%u	    显示无符号整数
			%f		显示浮点数			 
			%s		显示字符串			
			%%		显示%本身				
		修饰符:
			%#[.#]	第一个#控制显示宽度,第二个#表示小数点后的精度,例如%3.1f
			%-		左对齐,%-15s
			%+		显示数值的正负符号,%+d

示例:

awk -F ':' -v OFS='#' '{print NR,NF,$1}' /etc/passwd

数组

awk的数组是关联数组(即key/value方式的hash数据结构),索引下标可为数值(甚至是负数、小数等),也可为字符串,其实是map

  • awk数组的索引实际都是字符串,即使是数值索引在使用时内部也会转换成字符串
  • awk的数组元素的遍历顺序和插入顺序很可能是不同的
定义
awk 'BEGIN{
    arr[1]= 11 
    arr[-1]  = -11 ;
    arr[4.3] = 4.33 ;
    arr["1"] = 111  ;
    arr["a"] = "aa"  ;
    arr["x","y"] = 123 ;
    print arr[1];
}'
长度

length()函数获取数组长度

awk 'BEGIN{
    arr[1]= 11;
    arr[2]  = -11 ;
    arr[3] = 4.33 ;
    arr[4] = 111  ;
    arr[5] = "aa"  ;
    arr[6] = 123 ;
    print length(arr);
}'
删除
  • 删除元素: delete arr[idx] : 删除数组arr[idx]元素,允许删除不存在的元素
  • 删除数组:delete arr
判断类型

isarray(arr)可用于检测arr是否是数组,如果是数组则返回1,否则返回0

判断元素是否存在
# 错误示例
if(arr["x"] != ""){...}
  • 如果不存在arr[“x”],则会立即创建该元素,并将其值设置为空字符串
  • 有些元素的值本身就是空字符串
# 正确示例:使用'in',如果存在则返回1,不存在则返回0
if (i in arr){...}
遍历数组
for(i in arr) { 
	print arr[idx]
}

awk 'BEGIN{
    arr[1]= 11 
    arr[2]  = -11 ;
    arr[3] = 4.33 ;
    arr[4] = 111  ;
    arr[5] = "aa"  ;
    arr[6] = 123 ;
    for (i in arr) {print i};
}'

运算符

运算符列表如下,运算符优先级参考C语言。

运算符名称 含义
(...) 运算组
$ 取值
in 数组成员
space 字符串拼接,例如:12 " " 23
? : 三目运算符
+ - * / % 算术运算符:加、减、乘、除、求余
++ -- 算术运算符:自加、自减,支持前置、后置
^ 算术运算符:幂
&& || ! 逻辑运算符:与、或、非
< > <= >= != == 比较运算符:小于、大于、小于等于、大于等于、不等于、等于
~ !~ 正则匹配运算符:正则匹配、正则匹配取反,返回值:1为匹配成功,0为匹配失败
= += -= *= /= %= ^= 赋值运算符

示例:

awk 'BEGIN{
	a=(10+2-3)*4; print a;
	a=a/5; print a;
	a=a%5; print a;
	a=int(a%5); print a;	
	a=2^10; print a;
	a=log(100); print a;
	print (a > 0 ? "true" : "false");
	b="a1b2c3";print b ~ "b2";
}'

流程控制

  • if (condition) statement [ else if (condition) statement ] [ else statement ]

  • while (condition) statement

  • do statement while (condition)

  • for (expr1; expr2; expr3) statement

  • for (var in array) statement

  • break

  • continue

  • next : 读取下一行并附带continue动作

  • nextfile : 读取下一个文件

  • exit [ expression ] : 退出awk程序

  • switch (expression) {

    case value|regex : statement

    ...

    [ default: statement ]

    }

# if : 单行输出1,双行输出2
awk -F :  '{if(NR % 2 == 0) print NR,2; else print NR,1}' /etc/passwd

# while循环

# for循环
awk -F: '{for(i=10;i>0;i--){print $0}}' /etc/passwd

内置函数

数字函数
  • atan2(y, x) 求y/x的反正切值

  • cos(expr) 求余弦

  • exp(expr) 求指数

  • int(expr) 数字截断转换为整数

  • log(expr) 求对数.

  • rand() 生成≤0且< 1的随机数

  • sin(expr) 求正弦值

  • sqrt(expr) 请平方根

  • srand([expr]) 获取随机数,以expr作为随机数生成的种子,如果未设置以当前时间作为种子

字符串函数
  • asort(s [, d [, how] ])
    返回源数组 s 中的元素数量。使用 gawk  比较值的正常规则对 s 的内容进行排序,并将排序值 s 的索引替换为以下开头的连续整数1. 如果指定了可选目标数组d,则首先将s复制到d中,然后对d进行排序,保持源数组 s 的索引不变。可选字符串how控制方向和比较模式。

  • asorti(s [, d [, how] ])
    返回源数组 s 中的元素数量。其行为与 asort() 相同,只是使用数组索引进行排序,而不是数组值。完成后,数组将以数字方式索引,并且值是原始索引的值。原始值丢失;因此,如果您希望保留原始数组,请提供第二个数组。可选字符串how的用途与asort()相同

  • gensub(r, s, h [, t])

    在目标字符串 t 中搜索正则表达式 r 的匹配项。如果 h 是以 gG 开头的字符串,则将 r 的所有匹配项替换为 s 。否则,h 是一个数字,指示要替换 r 的哪个匹配项。如果未提供 t,请使用 $0 代替。在替换文本 s 中,序列 n,,其中 n 是从 1 到 9 的数字,可以用于指示仅与第 n 个括号子表达式匹配的文本。序列 \0 代表整个匹配文本,字符 & 也是如此。与sub()gsub()不同,修改后的字符串作为函数的结果返回,而原始目标字符串没有改变。

  • gsub(r, s [, t])

    对于字符串t中与正则表达式r匹配的每个子字符串,替换字符串s,并返回替换次数。如果未提供t,请使用$0。替换文本中的 & 将替换为实际匹配的文本。使用 & 获取文字 &

  • index(s, t)

    返回字符串 s 中字符串 t 的索引,如果 t 不存在则返回0。 (这意味着字符索引从 1 开始。)

  • length([s])

    返回字符串 s 的长度,如果未提供 s,则返回 $0 的长度。对于数组参数,length() 返回数组中的元素数量

  • match(s, r [, a])

    s是代表字符串,r代表正则表达式,match的作用是返回匹配r的子串在s中的首个位置

  • patsplit(s, a [, r [, seps] ])

    根据正则表达式r将字符串s拆分为数组a和分隔符数组seps,并返回字段数量。元素值是 s 中与 r 匹配的部分。 seps[i] 的值是 a[i 之后出现的可能为空的分隔符]. seps[0] 的值是可能为空的前导分隔符。如果省略r,则使用FPAT。首先清除数组aseps。拆分的行为与使用 FPAT 进行字段拆分的行为相同

  • split(s, a [, r [, seps] ])

    根据正则表达式r将字符串s拆分为数组a和分隔符数组seps,并返回字段数量。如果省略r,则使用FS。首先清除数组asepsseps[i]a[< 之间与 r 匹配的字段分隔符em>i]a[i+1]。 拆分的行为与字段拆分相同

  • sprintf(fmt , expr-list)

    根据fmt打印expr-list,并返回结果字符串

  • strtonum(str)

    检查str,并返回其数值。如果 str 以前导 0 开头,则将其视为八进制数。如果str以前导0x0X开头,则将其视为十六进制数。否则,假设它是十进制数

  • sub(r, s [, t])

    就像gsub()一样,但只替换第一个匹配的子字符串。返回零或一。

  • substr(s, i [, n])

    返回从 i 开始的 s 中最多 n 个字符的子字符串。如果省略n,则使用其余的s

  • tolower(str)

    返回字符串 str 的副本,其中 str 中的所有大写字符均转换为相应的小写字符。非字母字符保持不变。

  • toupper(str)

    返回字符串 str 的副本,其中 str 中的所有小写字符均转换为相应的大写字符。非字母字符保持不变。

时间函数
  • mktime(datespec [, utc-flag])

    datespec转换为与systime()返回的形式相同的时间戳,并返回结果。如果 utc-flag 存在且非零或非空,则假定时间位于 UTC 时区;否则,时间被假定为本地时区。如果datespec不包含足够的元素或者结果时间超出范围,mktime()返回-1

  • strftime([format [, timestamp[, utc-flag]]])

    根据格式中的规范设置时间戳的格式。如果 utc-flag 存在且非零或非空,则结果采用 UTC 格式,否则结果采用当地时间。 时间戳应该与systime()返回的形式相同。如果时间戳丢失,则使用当前时间。如果缺少 format,则使用与 date(1) 的输出等效的默认格式。默认格式可在 PROCINFO["strftime"] 中找到。请参阅 ISO C 中的 strftime() 函数规范,了解保证可用的格式转换

  • systime()

    返回当前时间作为自纪元(POSIX 系统上的 1970-01-01 00:00:00 UTC)以来的秒数

位操作函数
  • and(v1, v2 [, ...])

    返回参数列表中提供的值的按位与。必须至少有两个。

  • compl(val)

    返回 val 的按位补码。

  • lshift(val, count)

    返回 val 的值,左移 count 位。

  • or(v1, v2 [, ...])

    返回参数列表中提供的值的按位或。必须至少有两个。

  • rshift(val, count)

    返回 val 的值,右移 count 位。

  • xor(v1, v2 [, ...])

    返回参数列表中提供的值的按位异或。必须至少有两个

功能函数
  • isarray(x)

    如果 x 是数组,则返回 true,否则返回 false

  • typeof(x) (注:4.2及以上版本持此函数)

    返回一个字符串,指示 x 的类型。该字符串将为 "array"、"number"、"regexp"、"string" 之一, “strnum”、“未分配”或“未定义”

自定义函数

函数定义
# 声明函数
function name(parameter list) { statements }

# 引用函数
@include "filename" pattern   { action statements }
函数参数
  • 函数参数声明类型与传递的值类型不一致将报错
  • 数组参数是引用传递,其他为值传递
函数返回值

函数返回值使用return语句

函数变量作用域

与shell脚本类似,函数内变量的作用域为全局作用域

linux分区修复

查看分区信息

# 查看分区列表
cat /etc/fstab

# 查看挂载情况
df -h

# 查看硬盘分区的详细信息
fdisk -l

# 查看硬盘分区的概要信息
lsblk

#查看文件系统类型信息(包含UUID)
blkid

修复分区

# 卸载分区
umount 分区名

# 如果非逻辑分区使用fsck
fsck -y 分区名

# 如果使用的XFS文件系统
xfs_check 分区名
xfs_repair 分区名

Linux信息获取

# 系统启动时间
uptime -s

# 获取硬盘序列号(虚拟机无法获取)
lsblk --nodeps -no serial /dev/sda

# 查看设备序列号
dmidecode -t 1
posted @ 2025-01-13 17:41  孤独的天  阅读(153)  评论(0)    收藏  举报