linux shell脚本攻略 笔记

shell参数扩展

${parameter:+expression}

如果parameter有值且不为空,则使用expression的值。
效果:
在这里插入图片描述
${usage/%/} 是一个字符串替换操作,其中 usage 是变量名,% 是要被替换的字符(百分号),空字符 ‘’ 是替换后的内容。这个命令的作用是将变量 usage 中的所有百分号(%)替换为空字符。

[root@HBJ-001 rsyslog.d]#echo ${usage/\%/}
71
[root@HBJ-001 rsyslog.d]# echo ${usage/\%/*/}
71*/
[root@HBJ-001 rsyslog.d]# echo ${usage/\%/*} 
71*

VAR=sample.jpg

**取文件名称以及后缀名**
${VAR%.*}得到文件名 #移除.*所匹配的最右边的内容$VAR中删除位于%右侧的通配符(在上例中是.*)所匹配的字符串。通配符从右向左进行匹配。即VAR=sample.jpg。通配符从右向左匹配到的内容是.jpg,因此从$VAR中删除匹配结果,得到输出sample。
%属于非贪婪(non-greedy)操作。它从右向左找出匹配通配符的最短结果。还有另一个操作符%%,它与%相似,但行为模式却是贪婪的,这意味着它会匹配符合通配符的最长结果。
区别:VAR=hack.fun.book.txt
echo ${VAR%.*}   命令输出:hack.fun.book
echo ${VAR%%.*}  命令输出:hack  #将从右边开始一直匹配到最左边的.*(贪婪操作符)移除
${VAR#*.}得到后缀名
从$VARIABLE中删除位于#右侧的通配符(即在上例中使用的*.)从左向右所匹配到的字符串。和%%类似,#也有一个对应的贪婪操作符##。
VAR=hack.fun.book.txt
echo ${VAR#*.} 命令输出:fun.book.txt(使用#操作符从左向右执行非贪婪匹配,得到匹配结果hack:)
echo ${VAR##*.} 命令输出:txt。(使用##操作符从左向右执行贪婪匹配,得到匹配结果hack.fun.book:)
这里有个能够提取域名中不同部分的实例。假定URL为www.google.com
$ echo ${URL%.*} # 移除.*所匹配的最右边的内容
www.google
$ echo ${URL%%.*} # 将从右边开始一直匹配到最左边的.*(贪婪操作符)移除
www
$ echo ${URL#*.} # 移除*.所匹配的最左边的内容
google.com
$ echo ${URL##*.} # 将从左边开始一直匹配到最右边的*.(贪婪操作符)移除
com

替换变量内容中的部分文本:

$ var="This is a line of text"
$ echo ${var/line/REPLACED}
This is a REPLACED of text"
我们可以通过指定字符串的起始位置和长度来生成子串
${variable_name:start_position:length}
[root@H-001 bot]# echo $var
This is a line of text
[root@H-001 bot]# echo ${var:1:5}
his i
#(-1)表示的就是最后一个字符的索引
[root@H-001 bot]#echo ${var:(-1)}  
t
输出变量的长度:
echo ${#var}

用户,组管理

usermod, gpasswd

#将mysql加入rpc组
usermod -aG rpc mysql
#将mysql移出rpc组
gpasswd -d mysql rpc
#更改用户shell
chsh USER -s SHELL
#设置用户过期时间
chage -E DATE
chage -l命令会显示用户账户的过期信息。
#锁定与解锁用户
usermod -L user
usermod -U user

bc数学运算,需先安装bc

  • bc进制转换
[root@HFS-OP-OPENRESTR-01 ~]# echo "obase=2;$num" | bc
1100100
[root@HFS-OP-OPENRESTR-01 ~]# echo "obase=10;ibase=2;1100100"|bc
100
  • 设定小数精度
[root@HFS-OP-OPENRESTR-01 ~]# echo "scale=2;22/7" | bc
3.14
  • 计算平方以及平方根。
[root@HFS-OP-OPENRESTR-01 ~]# echo "sqrt(100)" | bc
10
[root@HFS-OP-OPENRESTR-01 ~]# echo "10^10" | bc
10000000000

tee命令可以将数据重定向到文件,还可以提供一份重定向数据的副本作为管道中后续
命令的stdin。tee命令从stdin中读取,然后将输入数据重定向到stdout以及一个或多个文件中。

command | tee FILE1 FILE2 | otherCommand
-a选项,可用于追加内容
tee -a out.txt

自定义文件描述符

exec命令创建全新的文件描述符
 只读模式。
 追加写入模式。
 截断写入模式。
<操作符可以将文件读入stdin。>操作符用于截断模式的文件写入(数据在目标文件内容被
截断之后写入)。>>操作符用于追加模式的文件写入(数据被追加到文件的现有内容之后,而且
该目标文件中原有的内容不会丢失)。文件描述符可以用以上3种模式中的任意一种来创建。
创建一个用于读取文件的文件描述符:

#创建一个用于读取文件的文件描述符:
[root@HFS-OP-OPENRESTR-01 ~]# touch input
[root@HFS-OP-OPENRESTR-01 ~]# exec 3<input
[root@HFS-OP-OPENRESTR-01 ~]# echo 12345 > input
[root@HFS-OP-OPENRESTR-01 ~]# cat input 
12345
[root@HFS-OP-OPENRESTR-01 ~]# cat <&3
12345
#创建一个用于写入(追加模式)的文件描述符
[root@HFS-OP-OPENRESTR-01 ~]# exec 5>>input.txt
[root@HFS-OP-OPENRESTR-01 ~]# echo 123 >&5
[root@HFS-OP-OPENRESTR-01 ~]# cat input.txt 
123
[root@HFS-OP-OPENRESTR-01 ~]# echo 123a >&5 
[root@HFS-OP-OPENRESTR-01 ~]# cat input.txt 
123
123a
#用于写入(截断模式)的文件描述符,即是以下这种方式
exec 6>input.txt

数组与关联数组

Bash支持普通数组和关联数组,前者使用整数作为数组索引,后者使用字符串作为数组索引
定义数组

  • 可以在单行中使用数值列表来定义一个数组:
array_var=(test1 test2 test3 test4) 

#这些值将会存储在以0为起始索引的连续位置上
另外,还可以将数组定义成一组“索引值”:

array_var[0]="test1"
array_var[1]="test2"
array_var[2]="test3"
array_var[3]="test4"
array_var[4]="test5"
array_var[5]="test6"
  • 打印出特定索引的数组元素内容:
#打印出所有的值
[root@HFS-OP-OPENRESTR-01 ~]# echo ${array_var[*]}
test1 test2 test3 test4
[root@HFS-OP-OPENRESTR-01 ~]# echo ${array_var[@]}
test1 test2 test3 test4
#打印指定索引的值
[root@HFS-OP-OPENRESTR-01 ~]# echo ${array_var[1]}
test2
#打印数组长度
[root@HFS-OP-OPENRESTR-01 ~]# echo ${#array_var[@]}
4
[root@HFS-OP-OPENRESTR-01 ~]# echo ${#array_var[*]}
4

关联数组
在关联数组中,我们可以用任意的文本作为数组索引。首先,需要使用声明语句将一个变量
定义为关联数组

[root@HFS-OP-OPENRESTR-01 ~]# declare -A ass_array2 
#使用独立的“索引值”进行赋值: 
$ ass_array[index1]=val1
$ ass_array'index2]=val2
#使用行内“索引值”列表:   
[root@HFS-OP-OPENRESTR-01 ~]# ass_array2=([index1]=val1 [index2]=val2)
[root@HFS-OP-OPENRESTR-01 ~]# echo ${ass_array2[*]}
val1 val2
[root@HFS-OP-OPENRESTR-01 ~]# echo ${ass_array2[index1]}
val1
[root@HFS-OP-OPENRESTR-01 ~]# echo ${ass_array2[index2]}
val2

列出数组索引

echo ${!array_var[*]}
echo ${!array_var[@]}
[root@HFS-OP-OPENRESTR-01 ~]# echo ${!ass_array2[*]}    
index1 index2
[root@HFS-OP-OPENRESTR-01 ~]# echo ${!array_var[@]}
0 1 2 3

对别名进行转义

$ \command
字符\可以转义命令,从而执行原本的命令

[root@HFS-OP-OPENRESTR-01 ~]# alias 
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

在不可信环境下执行特权命令时,在命令前加上\来忽略可能存在的别名总是一种良好的安全实践。

我们可以使用不同的条件标志测试各种文件系统相关的属性。
● [ -f $file_var ]:如果给定的变量包含正常的文件路径或文件名,则返回真。
● [ -x $var ]:如果给定的变量包含的文件可执行,则返回真。
● [ -d $var ]:如果给定的变量包含的是目录,则返回真。
● [ -e $var ]:如果给定的变量包含的文件存在,则返回真。
● [ -c $var ]:如果给定的变量包含的是一个字符设备文件的路径,则返回真。
● [ -b $var ]:如果给定的变量包含的是一个块设备文件的路径,则返回真。
● [ -w $var ]:如果给定的变量包含的文件可写,则返回真。
● [ -r $var ]:如果给定的变量包含的文件可读,则返回真。
● [ -L $var ]:如果给定的变量包含的是一个符号链接,则返回真。

当用户登录shell时,会执行下列文件:

/etc/profile, $HOME/.profile, $HOME/.bash_login, $HOME/.bash_profile /

如果你是通过图形化登录管理器登入的话,是不会执行/etc/profile、$HOME/.profile和$HOME/.bash_profile这3个文件的。
如果.bash_profile或.bash_login文件存在,则不会去读取.profile文件
交互式shell(如X11终端会话)或ssh执行单条命令(如ssh 192.168.1.1 ls /tmp)时,
会读取并执行以下文件:

/etc/bash.bashrc (/etc/bashrc ) $HOME/.bashrc  

当用户登出会话时,会执行下列文件:

$HOME/.bash_logout

find命令
-prune用于排队某个目录,需要写在前面

find命令支持逻辑操作符。-a和-and选项可以执行逻辑与(AND)操作,-o和-or选项可以执行逻辑或(OR)操作。
find / -name data -prune -o -type f ! -perm 755 -print

-path选项可以限制所匹配文件的路径及名称。例如,$ find /home/users -path
/slynux/’ -name ‘*.txt’ –print能够匹配文件/home/users/slynux/readme.txt,但无法匹
配/home/users/slynux.txt。
-regex选项和-path类似,只不过前者是基于正则表达式来匹配文件路径的。
-iregex选项可以让正则表达式在匹配时忽略大小写
-maxdepth和–mindepth选项可以限制find命令遍历的目录深度。这可以避免find命令没完没了地查找。

find -L /proc -maxdepth 1 -name 'bundlemaker.def' 2>/dev/null
 -L选项告诉find命令跟随符号链接
 从/proc目录开始查找
 -maxdepth 1将搜索范围仅限制在当前目录
 -name 'bundlemaker.def'指定待查找的文件
 2>/dev/null将有关循环链接的错误信息发送到空设备中
**按天数**
 访问时间(-atime):用户最近一次访问文件的时间。
 修改时间(-mtime):文件内容最后一次被修改的时间。
 变化时间(-ctime):文件元数据(例如权限或所有权)最后一次改变的时间。
**按分钟数**
 -amin(访问时间);
 -mmin(修改时间);
 -cmin(变化时间)。

xargs
xargs有一个选项-I,可以用于指定替换字符串,这个字符串会在xargs解析输入时被参数替换掉,使用-I的时候,命令以循环的方式执行。如果有3个参数,那么命令就会连同{}一起被执行3次。{}会在每次执行中被替换为相应的参数。

运行结果:
find . -name '*.c' | xargs -I ^ sh -c "echo -ne '\n ^: '; grep -n main ^"
#xargs -I ^ 表示将每个文件名替换为变量 ^
 ./1.c: 1:main

 ./2.c: 4:main

 ./3.c: 4:main
 find . -name '*.c' | xargs -I aa sh -c "echo -ne '\n aa: '; grep -n main aa" 

 ./1.c: 1:main

 ./2.c: 4:main

 ./3.c: 4:main
 === === === === === === === === === === === === === === === === === === ===
cat 1.c 
main
cat 2.c  
11
22
33
main

split命令可以用来分割文件

dd if=/dev/zero of=/tmp/haha bs=10k count=50 
split -b 50k haha #分割成10文件
#split默认使用字母后缀。如果想使用数字后缀,需要使用-d选项。此外, -a length可以指定后缀长度,可以使用 -l no_of_lines按照行数来分割
cat xa* > haha2 #合并文件
[root@HB tmp]# md5sum haha
816df6f64deba63b029ca19d880ee10a  haha
[root@HB tmp]# md5sum haha2
816df6f64deba63b029ca19d880ee10a  haha2
#md5一致

csplit实用工具能够基于上下文来分隔文件。它依据的是行计数或正则表达式
看一个日志文件示例:
cat server.log

SERVER-1
[connection] 192.168.0.1 success
[connection] 192.168.0.2 failed
[disconnect] 192.168.0.3 pending
[connection] 192.168.0.4 success
SERVER-2
[connection] 192.168.0.1 failed
[connection] 192.168.0.2 failed
[disconnect] 192.168.0.3 success
[connection] 192.168.0.4 failed
SERVER-3
[connection] 192.168.0.1 pending
[connection] 192.168.0.2 pending
[disconnect] 192.168.0.3 pending
[connection] 192.168.0.4 failed

我们需要将这个日志文件分割成server1.log、server2.log和server3.log

csplit server.log /SERVER/ -n 2 -s {*} -f server -b "%02d.log"
下面是这个命令的详细说明。
 /SERVER/ 用来匹配特定行,分割过程即从此处开始。
 /[REGEX]/ 用于描述文本模式。它从当前行(第一行)一直复制到(但不包括)包含SERVER
的匹配行。
 {*} 表示根据匹配重复执行分割操作,直到文件末尾为止。可以用{整数}的形式来指定分
割执行的次数。
 -s 使命令进入静默模式,不打印其他信息。
 -n 指定分割后的文件名后缀的数字个数,例如01、02、03等。
 -f 指定分割后的文件名前缀(在上面的例子中,server就是前缀)。
 -b 指定后缀格式。例如%02d.log,类似于C语言中printf的参数格式。在这里:文件
名 = 前缀 + 后缀,也就是server + %02d.log。
转换文件名的大小写:
$ rename 'y/A-Z/a-z/' *
$ rename 'y/a-z/A-Z/' *
将 *.JPG更名为 *.jpg:
$ rename *.JPG *.jpg
将文件名中的空格替换成字符 "_":
$ rename 's/ /_/g' *

多目录切换

pushd和popd可以用于在多个目录之间切换而无需重新输入目录路径。这两个命令会创建一
个路径栈,它是一个保存了已访问目录的LIFO列表。只有两个路径的简便方法:cd -

#压入并切换路径
[root@node1 tmp]# pushd /home
/home /tmp /tmp
[root@node1 home]# dirs
/home /tmp /tmp
[root@node1 home]# pushd /etc
/etc /home /tmp /tmp
#查看栈的内容
[root@node1 etc]# dirs
/etc /home /tmp /tmp
#0     1     2     3
[root@node1 etc]# pushd +1
/home /tmp /tmp /etc
[root@node1 home]# pwd
/home
[root@node1 home]# dirs
/home /tmp /tmp /etc
#当你想切换到栈中任意一个路径时,将每条路径从0编号到n,然后使用你希望切换到的路径编号
[root@node1 home]# pushd +3
/etc /home /tmp /tmp
#删除最近压入的路径并切换到下一个目录
[root@node1 etc]# popd 
/home /tmp /tmp
[root@node1 home]# popd
/tmp /tmp
[root@node1 tmp]# popd
/tmp

权限

目录有一个叫作粘滞位(sticky bit)的特殊权限。如果目录设置了粘滞位,只有创建该目录
的用户才能删除目录中的文件,就算用户组和其他用户也有写权限,仍无能无力。粘滞位出现在
其他用户权限组中的执行权限(x)位置。它使用t或T来表示。如果没有设置执行权限,但设置
了粘滞位,就使用T;如果同时设置了执行权限和粘滞位,就使用t。例如:
------rwt , ------rwT
设置目录粘滞位的一个典型例子就是/tmp,也就是说任何人都可以在该目录中创建文件,
但只有文件的所有者才能删除其所创建的文件。
可以使用chmod的+t选项设置:

chmod a+t directory_name

以不同的身份运行可执行文件(setuid)
一些可执行文件需要以另一种身份来运行。例如,http服务器会在系统启动期间由root负责
运行,但是该进程应该属于用户httpd。setuid权限允许其他用户以文件所有者的身份来执
行文件。setuid只能应用在Linux ELF格式的二进制文件上。你不能对脚本设置setuid。这是一种安
全特性。

chmod +s executable_file

将文件设置为不可修改
chattr命令可用于更改扩展属性。它能够将文件设置为不可修改,也可以修改其他属性来
调节文件系统同步或压缩率。
使用chatter将文件设置为不可修改:

chattr +i file

使用chatter将文件设置为只能追加

chattr +a file

diff命令可以生成两个文件之间的差异对比。

文件 1:version1.txt
this is the original text
line2
line3
line4
happy hacking !
文件 2:version2.txt
this is the original text
line2
line4
happy hacking !
GNU is not UNIX
(2) 非一体化(nonunified)形式的diff输出(不使用-u选项)如下:
$ diff version1.txt version2.txt
3d2
<line3
6c5
> GNU is not UNIX
(3) 一体化形式的diff输出如下:
$ diff -u version1.txt version2.txt
--- version1.txt 2010-06-27 10:26:54.384884455 +0530
+++ version2.txt 2010-06-27 10:27:28.782140889 +0530
@@ -1,5 +1,5 @@
this is the original text
line2
-line3
line4
happy hacking !
-
+GNU is not UNIX
选项-u用于生成一体化输出。因为一体化输出的可读性更好,更易于看出两个文件之间的差异,所以人们往往更喜欢这种输出形式。
在一体化diff输出中,以+起始的是新加入的行,以-起始的是被删除的行。
修补文件可以通过将diff的输出重定向到一个文件来生成:
diff -u version1.txt version2.txt > version.patch
用下列命令来进行修补:
patch -p1 version1.txt < version.patch
version1.txt的内容现在和version 2.txt一模一样了。
对已修补过的文件再修补将撤销作出的变更
patch -p1 version1.txt < version.patch 
patching file version1.txt
Reversed (or previously applied) patch detected! Assume -R? [n] y

文本文件的交集与差集

comm命令可用于比较两个已排序的文件(是comm必须使用两个排过序的文件作为输入)

$ cat A.txt
apple
orange
gold
silver
steel
iron
$ cat B.txt
orange
gold
cookies
carrot
$ sort A.txt -o A.txt ; sort B.txt -o B.txt
$ comm A.txt B.txt
apple
	carrot
	cookies
iron		gold
			orange
silver
steel
输出的第一列包含只在A.txt中出现的行,第二列包含只在B.txt中出现的行,第三列包含
A.txt和B.txt中共有的行。各列之间以制表符(\t)作为分隔符。

comm的命令行选项可以减少输出。
 -1:删除第一列。
 -2:删除第二列。
 -3:删除第三列。

打印两个文件的交集,我们需要删除前两列,只打印出第三列。-1选项可以删除第
一列,-2选项可以删除第二列,最后留下的就是第三列:
comm A.txt B.txt -1 -2

删除第三列,就可以打印出两个文件中互不相同的那些行:
comm A.txt B.txt -3


正则:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
cut命令可以按列,而不是按行来切分文件
在cut的术语中,每列被称为一个字段,选项**-f可以指定要提取的字段,–complement**选项显示出没有被-f指定的那些字段,选项-d能够设置分隔符,–output-delimiter可以指定输出分隔符
在这里插入图片描述
下列选项将字段指定为某个范围内的字节、字符或字段:
 -b 表示字节
 -c 表示字符
 -f 用于定义字段
第2个到第5个字符
cut -c2-5 range_fields.txt
打印前2个字符:
cut -c -2 range_fields.txt

sed

/#g标记可以使sed替换第N次出现的匹配:
\b是单词边界

# echo 11 abc 111 this 9 file contains 111 11 88 numbers 0000|sed "s/\b[0-9]\{3\}\b/fuck/2g"
输出:11 abc 111 this 9 file contains fuck 11 88 numbers 0000

已匹配字符串标记(&)
可以用&指代模式所匹配到的字符串,这样就能够在替换字符串时使用已匹配的内容:

$ echo this is an example | sed 's/\w\+/[&]/g'
[this] [is] [an] [example]

子串匹配标记(#)
&指代匹配给定模式的字符串。我们还可以使用#来指代出现在括号中的部分正则表达式所匹配到的内容。对于匹配到的第一个子串,其对应的标记是\1,匹配到的第二个子串是\2,往后以此类推。

组合多个表达式
可以利用管道组合多个sed命令,多个模式之间可以用分号分隔,或是使用选项-e PATTERN:

sed 'expression' | sed 'expression'
sed 'expression; expression'
sed -e 'expression' -e 'expression'

awk

awk脚本的结构如下:

awk 'BEGIN{ print "start" } pattern { commands } END{ print "end" }' file

awk命令的工作方式如下。
(1) 首先执行BEGIN { commands } 语句块中的语句。
(2) 接着从文件或stdin中读取一行,如果能够匹配pattern,则执行随后的commands语句
块。重复这个过程,直到文件全部被读取完毕。
(3) 当读至输入流末尾时,执行END { commands } 语句块。

awk脚本通常由3部分组成:BEGIN、END和带模式匹配选项的公共语句块(common statement
block)。这3个部分都是可选的,可以不用出现在脚本中。
awk以[逐行的形式]处理文件。BEGIN之后的命令会先于公共语句块执行。对于匹配PATTERN
的行,awk会对其执行PATTERN之后的命令。最后,在处理完整个文件之后,awk会执行END之后
的命令。

例子:

awk 'BEGIN { statements } { statements } END { end statements }'
可以看出有多少行i就是+了多少次,也就是逐行处理
[root@HBJ-001 bot]# echo 1 2|awk 'BEGIN { i=0 } { i++ } END { print i}'
1
[root@HBJ-001 bot]# echo -e "1\n2\n"|awk 'BEGIN { i=0 } { i++ } END { print i}'   
3
[root@HBJ-001 bot]# echo -e "1\n2"|awk 'BEGIN { i=0 } { i++ } END { print i}'  
2
  1. BEGIN语句块在awk开始从输入流中读取行之前被执行。这是一个可选的语句块,诸如变量初始化、打印输出表格的表头等语句通常都可以放在BEGIN语句块中。
  2. END语句块和BEGIN语句块类似。它在awk读取完输入流中所有的行之后被执行。像打印所有行的分析结果这种常见任务都是在END语句块中实现的。
  3. 最重要的部分就是和pattern关联的语句块。这个语句块同样是可选的。如果不提供,则默 认执行{ print },即打印所读取到的每一行。awk对于读取到的每一行都会执行该语句块。这就像一个用来读取行的while循环,在循环体中提供了相应的语句。
  4. 每读取一行,awk就会检查该行是否匹配指定的模式。模式本身可以是正则表达式、条件语 句以及行范围等。如果当前行匹配该模式,则执行{}中的语句。

awk命令是一个解释器,它能够解释并执行程序,和shell一样,它也包括了一些特殊变量。

 NR:表示记录编号,当awk将行作为记录时,该变量相当于当前行号。每读入一行,awk都会更新NR
 NF:表示字段数量,在处理当前记录时,相当于字段数量。默认的字段分隔符是空格。
 $0:该变量包含当前记录的文本内容。
 $1:该变量包含第一个字段的文本内容。
 $2:该变量包含第二个字段的文本内容。

将外部变量值传递给awk

$ VAR=10000
$ echo | awk -v VARIABLE=$VAR '{ print VARIABLE }'
10000
---
$ var1="Variable1" ; var2="Variable2"
$ echo | awk '{ print v1,v2 }' v1=$var1 v2=$var2
Variable1 Variable2
---
$ awk '{ print v1,v2 }' v1=$var1 v2=$var2 filename #(当输入来自于文件)

用getline读取行
awk默认读取文件中的所有行。如果只想读取某一行,可以使用getline函数。它可以用于在BEGIN语句块中读取文件的头部信息,然后在主语句块中处理余下的实际数据。
该函数的语法为:getline var。变量var中包含了特定行。如果调用时不带参数,我们可以用 $0、$1和$2访问文本行的内容。例如:

seq 5 | awk 'BEGIN { getline; print "Read ahead first line", $0 } { print $0 }'

使用过滤模式对awk处理的行进行过滤

$ awk 'NR < 5' # 行号小于5的行
$ awk 'NR==1,NR==4' # 行号在1到5之间的行
$ awk '/linux/' # 包含模式为linux的行(可以用正则表达式来指定模式)
$ awk '!/linux/' # 不包含模式为linux的行
选项-F指定不同的分隔符:
$ awk -F: '{ print $NF }' /etc/passwd
awk 'BEGIN { FS=":" } { print $NF }' /etc/passwd

#打印位于模式start_pattern与end_pattern之间的文本:
awk '/start_pattern/, /end_pattern/' filename
$ cat section.txt
#输出
line with pattern1
line with pattern2
line with pattern3
line end with pattern4
line with pattern5
awk '/pa.*3/, /end/' section.txt
#输出
line with pattern3
line end with pattern4

从awk中读取命令输出
下面的代码从/etc/passwd文件中读入一行,然后显示出用户登录名及其主目录。在BEGIN语句块中将字段分隔符设置为:,在主语句块中调用了grep。

$ awk 'BEGIN {FS=":"} { "grep root /etc/passwd" | getline; \
print $1,$6 }'
root /root

在awk中使用循环

#for循环,其格式与C语言中的差不多
for(i=0;i<10;i++) { print $i ; }
#awk还支持列表形式的for循环,也可以显示出数组的内容:
for(i in array) { print array[i]; }

awk有很多内建的字符串处理函数。

 length(string):返回字符串string的长度。
 index(string, search_string):返回search_string在字符串string中出现的位置。
 split(string, array, delimiter):以delimiter作为分隔符,分割字符串string,
将生成的字符串存入数组array。
 substr(string, start-position, end-position) : 返回字符串string 中以
start-position和end-position作为起止位置的子串。
 sub(regex, replacement_str, string):将正则表达式regex匹配到的第一处内容
替换成replacment_str。
 gsub(regex, replacement_str, string):和sub()类似。不过该函数会替换正则
表达式regex匹配到的所有内容。
 match(regex, string):检查正则表达式regex是否能够在字符串string中找到匹配。
如果能够找到,返回非0值;否则,返回0。match()有两个相关的特殊变量,分别是RSTART
和RLENGTH。变量RSTART包含了匹配内容的起始位置,而变量RLENGTH包含了匹配内容
的长度。
egrep -o "\b[[:alpha:]]+\b" /etc/passwd|awk '{count[$0]++}END{printf ("%-14s%s\n","word","count"); for (i in count){printf ("%-14s%d\n", i,count[i])}}'
word          count
adm           3
to            1
sync          3
mail          3
egrep命令将文本文件转换成单词流,每行一个单词。模式\b[[:alpha:]]+\b能够匹配每个单词并去除空白字符和标点符号。选项-o打印出匹配到的单词,一行一个。
awk命令统计每个单词。它针对每一行文本执行{}语句块中的语句,因此我们不需要再专门为此写一个循环。count[$0]++命令负责计数,其中$0是当前行,count是关联数组。所有的行处理完毕后,END{}语句块打印出各个单词及其数量。

paste命令实现按列合并

paste file1.txt file2.txt
默认的分隔符是制表符,也可以用-d指定分隔符:
paste file1.txt file2.txt -d ","

tac命令 逆序形式打印行

日志轮转

logrotate能够限制日志文件的大小。系统的日志记录程序将信息添加到日志文件的同时并不会删除先前的数据。日志文件因此会变得越来越大。logrotate命令根据配置文件扫描特定的日志文件。它只保留文件中最近添加的100KB内容(假设指定了SIZE = 100k),将多出的数据(旧的日志数据)不断移入新文件logfile_name.1。当该文件(logfile_name.1)中的内容超出了SIZE的限定, logrotate 会将其重命名为logfile_name.2 并再创建一个新的logfile_name.1 ① 。logrotate命令还会将旧的日志文件压缩成logfile_name.1.gz、logfile_name.2.gz,以此类推。

logrotate的配置文件位于/etc/logrotate.d/

/data/logs/openresty/*log {
    su root product 
    daily
    rotate 10
    missingok
    notifempty
    dateext
    compress
    olddir /data/backup/logs/openresty
    sharedscripts
    postrotate
        /bin/kill -USR1 $(cat /data/logs/openresty/nginx.pid 2>/dev/null) 2>/dev/null || :
    endscript
}
#这个logrotate自定义配置的作用是:
#指定日志文件路径为/data/logs/openresty/*log,即所有以*log结尾的日志文件。
#使用su root product命令切换到root用户,并执行名为product的命令。
#设置日志轮换周期为每天(daily)。
#设置日志文件保留10个备份。
#如果日志文件不存在,则不报错(missingok)。
#如果日志文件为空,则不进行轮换(notifempty)。
#在日志文件名后添加日期扩展名(dateext)。
#对日志文件进行压缩(compress)。
#将旧的日志文件备份到/data/backup/logs/openresty目录下。
#使用共享脚本(sharedscripts)来处理日志轮换。
#在日志轮换完成后,执行postrotate脚本。在这个脚本中,使用/bin/kill -USR1 $(cat /data/logs/openresty/nginx.pid 2>/dev/null) 2>/dev/null || :命令向Nginx进程发送USR1信号,以便重新打开日志文件。如果发送失败,则忽略错误。
#结束postrotate脚本。
/var/log/program.log {
missingok
notifempty
size 30k
compress
weekly
rotate 5
create 0600 root root
}
参 数						 描 述
missingok 		如果日志文件丢失,则忽略并返回(不对日志文件进行轮替)
notifempty 		仅当源日志文件非空时才对其进行轮替
size 30k 		限制执行轮替的日志文件的大小。可以用1M表示1MB
compress 		允许用gzip压缩旧日志文件
weekly 			指定执行轮替的时间间隔。可以是weekly、monthly、yearly或daily
rotate 5 		需要保留的旧日志文件的归档数量。在这里指定的是5,所以这些文件名将会是program.log.1.gz、program.log.2.gz … program.log.5.gz
create 0600 root root 	指定所要创建的归档文件的权限、用户以及用户组

跟踪调用

使用strace 跟踪系统调用
使用ltrace 跟踪动态库函数
ltrace的选项-S 能同时跟踪用户空间和系统空间的函数调用

检查各子系统的工具列表

 CPU:top、dstat、perf、ps、mpstat、strace和ltrace。
 网络:netstat、ss、iotop、ip、iptraf、nicstat、ethtool和lsof。
 磁盘:ftrace、iostat、dstat和blktrace。
 内存:top、dstat、perf、vmstat和swapon。

dstat可以按类别找出占用资源最多的进程。
 --top-bio:用于描述磁盘使用情况,可以显示出执行块I/O最多的进程。
 --top-cpu:用于描述CPU使用情况,可以显示出CPU占用率最高的进程。
 --top-io:用于描述I/O使用情况,可以显示出执行I/O操作最多的进程(通常是网络I/O)。
 --top-latency:用于描述系统负载情况,可以显示出延迟最高的进程。
 --top-mem:用于描述内存使用情况,可以显示出占用内存最多的进程。
下面的例子显示了CPU和网络的使用情况以及占用这两种资源最多的进程:
$ dstat -c --top-cpu -n --top-io

pidstat包含多种选项,可以生成各种输出。
 -d:输出I/O统计。
 -r:输出缺页故障和内存使用情况。
 -u:输出CPU使用情况。
 -w:输出任务切换(上下文切换)情况。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值