美文网首页
Linux Shell脚本攻略读书笔记III —— 常用命令 I

Linux Shell脚本攻略读书笔记III —— 常用命令 I

作者: Great_Bug | 来源:发表于2018-07-27 16:39 被阅读0次

    根据这段时间对于本书的阅读,总结了如下一些常用的命令

    1. find
    2. ps
    3. sed
    4. awk

    下面我就来说说她们

    find

    find 命令的工作方式如下: 沿着文件层次结构向下遍历,匹配符合条件的文件,执行相应的操作.默认时打印出文件或者目录
    基础语法为:

    $ find base_path # base_path 可以是任意位置 例如 /home 会从home文件夹开始向下一次查找
    

    如下图[find 1]所示


    find 1

    find命令有多个选项配合过滤文件以及文件夹例如:

    -type 选项可以指定文件类型
    文件类型 类型参数
    普通文件 f
    符号链接 l
    目录 d
    字符设备 c
    块设备 b
    套接字 s
    FIFO p
    $ find /home -type d #这里只会打印出类型是文件夹的信息
    $ find /home -type f #这里只会打印出普通文件的信息
    
    -name 指定待查文件名的模式. 可以使通配符
    $ find -name '*.txt'  #查询后缀为txt的文件
    

    可以在name选项使用逻辑操作符 如下 :

    $ find /home \( -name '*.txt' -o -name '*.sh'  \) #查询后缀为txt或者sh的文件
    
    -regex 使用正则表达式查找文件
    $ find /home -regex '.*\(\.txt\|\.sh\)$' # 查询满足后缀为txt或者sh的文件 
    
    -mindepth -maxdepth 指定查找的目录深度
    $ find . -mindepth 2 -maxdepth 5 #表示向下查询深度从第二层目录开始 到 第五层目录
    
    根据文件时间戳过滤
    时间类型 参数类型
    访问时间 -atime
    修改时间 -mtime
    变化时间 -ctime

    配合整数参数指定天数.在参数前可使用+ - 表示大于 小于
    例如:

    $ find /home -atime +7 #表示找出访问时间超过7天的文件
    $ find /home -mtime -7 #表示找出访问时间在7天以内的文件
    $ find /home -ctime 7 #表示找出文件元数据修改时间等于7天的
    

    可以使用对应的 -amin -mmin -cmin 以分钟为记时单位的选项
    -newer 选项可以指定一个参照文件 以该参照文件的最近修改时间进行比较
    例如:

    $ find /home -newer xxx.txt #找出比xxx.txt文件修改时间更近的文件
    
    -size选项 指定文件大小进行过滤
    $ find . -type f -size 2k #删除大小为2k的普通文件
    $ find . -type f -size +2k #删除大小大于2k的普通文件
    $ find . -type f -size -2k #删除大小小于2k的普通文件
    
    字节单位 描述
    b 块(512字节)
    c 字节
    w 子(2字节)
    k 1024字节
    M 1024k字节
    G 1024M字节
    利用find执行相应的操作

    find命令可以对其所查询到的文件执行相应的操作
    -delete 命令可以删除查询到的文件 例如:

    $ find /home -type f -name '*.txt' -delete #意为删除/home目录下后缀为txt的普通文件
    

    find 命令可以通过-exec选项指定要做的操作 例如:

    $ find /home -type f -name 'xxx.txt' -exec rm {} \; #这里表示删除xxx.txt文件 {}表示查询到的文件名 这里使用\ 对分号进行转义 否则shell会其视为find命令结束导致-exec无法获得参数
    

    若find查询到的文件很多,可能会造成不小的开销那么这时候可以在命令最后使用+ 生成一份包含所有搜索结果的列表 一次性执行 例如:

    $ find /home -type f -name '*txt' -exec rm {} +
    

    PS

    ps命令可以报告活跃进程的相关信息.包括,拥有进程的用户,进程的起始时间,进程对应的命令路径,PID,进程所属的终端(TTY),进程使用的内存,进程占用的CPU等。
    执行如下:

    $ps #ps默认显示当前终端所启动的进程,所显示的信息也比较少 如下
    
      PID TTY           TIME CMD
     1050 ttys000    0:00.10 /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp KCZhang
     1052 ttys000    0:00.61 -zsh
     2626 ttys001    0:00.27 /bin/zsh --login -i
      742 ttys007    0:00.08 /bin/zsh --login -i
    

    选项 -e(every) 和 -ax(all) 能够输出系统中运行的所有进程的信息 如下

    $ ps -e
    $ ps -ef
    $ ps -ax
    

    由于ps -ef 获取的信息量很大,通常会通过-o选项指定列进行过滤 如下:

    ps -eo comm,pcpu | head -5 #找出前五个进程 的comm和cpu使用率
    
    COMM              %CPU
    /sbin/launchd      0.0
    /usr/sbin/syslog   0.0
    /usr/libexec/Use   0.0
    /usr/libexec/kex   0.0
    

    -o 参数列表如下

    参数 描述
    pcpu cpu使用率
    pid 进程id
    ppid 父进程id
    pmem 内存占用率
    comm 可执行文件名
    cmd 简单命令
    user 启动进程的用户
    nice 优先级
    time 累计的cpu时间
    etime 启动进程后的运行时长
    tty 所关联的tty设备(终端)
    euid 有效用户id
    stat 进程状态

    ps -u 可根据用户进行过滤

    $ ps -u root #查询有root用户创建的进程
    

    -u选项如果配合-e选项 则不会有过滤效果 因为-e会显示所有的进程

    PS内容进行排序
    ps -eo comm,pcpu --sort -pcpu #找出所有进程的comm pcpu 字段并按照pcpu进行降序排列 -pcpu表示降序 +pcpu表示升序
    

    ps -t 可根据tty进行过滤

    ps -t tty1 #显示tty设备为TTY1的信息 -t选项也不能和-e一起使用
    

    -LF选项显示进程的线程数以及线程id
    如下列举出线程数量最多的前五个进程:

    ps -eLF --sort -nlwp | head -5 
    

    ps -C 可以根据command name进行过滤


    sed

    sed是流编辑器的缩写, 一般用于文本替换。
    sed 可以使用一个字符串来替换匹配模式. 模式可以使字符串和正则表达式

    sed 's/pattern/replace_str/' file
    

    也可以从stdin读取

    cat file | sed 's/pattern/replace_str/'
    

    一般情况下,sed只是修改输出的内容并不会改变文本本身的数据。当然可以使用-i选项修改文件本身的数据。

    sed -i 's/pattern/replace_str/' file
    

    注意,在使用-i选项的时候只能使用file不能通过管道传递标准输入了
    以上的命令以及选项都只会匹配替换首次匹配上的内容,如果要替换所有匹配的内容需要这么做:

    sed 's/pattern/replace_str/g' file
    

    sed命令也可以结合正则表达式进行替换操作例如:

    $ sed 's/^$/d' file #删除所有的空格
    

    在sed中,可以用&指代模式所匹配到的字符串,这样就能在替换字符串时使用已经匹配到的内容,例如:

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

    还可以用\1 指代出现在括号中的部分正则表达式所匹配到的内容 例如:

    $ echo this is digit 7 in number | sed 's/digit \([0-9]\)/\1/'
    this is 7 in number
    

    这里就把digit 7 替换为了 7
    继续:

    $ echo seven SEVEN | sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1/'
    SEVEN seven
    

    这里\2表示第二个子匹配 \1 表示第一个子匹配 所以在输出进行了交换
    sed也可以组合多个表达式进行替换 多个模式之间可以用;分隔 或者使用| 或者使用-e选项 例子如下:

    $ echo abc | sed 's/a/A/' | sed 's/c/C/'
    AbC
    $ echo abc | sed 's/a/A/;s/c/C/'
    AbC
    $echo abc | sed -e 's/a/A/' -e 's/c/C/'
    AbC
    

    一般情况下sed 表达式内容使用单引号引用,如果会使用到变量那么使用双引号即可 如下:

    $ text=Hello
    $ echo Hello world | sed "s/$text/HELLO/"
    HELLO world
    

    awk

    awk是一个解释器,他能够解释并执行程序,支持关联数组,递归函数,条件语句等
    awk 脚本的结构如下:

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

    awk也能从标准输入stdin中读入读取输入
    下面的命令就利用了awk语法特性实现了文本行数的获取:

    $ awk 'BEGIN { i=0 } {i++} END {print i}' filename
    

    解释一下awk的工作流程:

    1. 首先执行BEGIN {command} 语句块
    2. 然后从文件或者标准输入中读取一行,如果能够匹配到pattern 则执行后面的command语句
    3. 重复执行第二步,知道文件读取完毕
    4. 当读到文件末尾时,执行END{command} 语句

    BEGIN 语句块在awk开始从输入流中读取之前执行,这个部分是可选的,一般会把变量初始化,表格表头信息放在这一部分定义

    END语句块于BEGIN对应,它在awk读取完毕之后执行。

    awk pattern可以使用正则表达式进行行的过滤,如下:

    $ echo -e "123\nabc" > awk_test.txt
    $ awk 'BEGIN{print "start"} /[a-z]+/ {print} END {print "end"} '
    start
    abc
    end
    $awk 'BEGIN{print "start"} /[0-9]+/ {print} END {print "end"} '
    start
    123
    end
    

    awk的特殊变量

    变量 描述
    NR 表示记录编号
    NF 字段数量
    $0 包含当前记录的文本内容
    $1 包含记录第一个字段的内容
    $2 包含记录第二个字段的内容

    例如

    $ echo -e "line1 f2 f3\nline2 f4 f5" | awk '{print "Line no : "NR", No of fields:"NF", $0="$0",$1="$1""}'
    Line no : 1, No of fields:3, $0=line1 f2 f3,$1=line1
    Line no : 2, No of fields:3, $0=line2 f4 f5,$1=line2
    

    $(NF) 可以获取到最后一个字段

    $(NF-1) 获取倒数第一个字段
    例如:

    $ echo "This is an example" | awk '{print $(NF)}'
    example
    $ echo "This is an example" | awk '{print $(NF-1)}'
    an
    

    awk可以根据选项-v将外部的变量传递到awk使用
    例如

    $ VAR=1000
    $ echo "VAR" | awk -v var1=$VAR '{print $0 var1}'
    VAR1000
    

    还有另一种方式如下:

    $ VAR=1000
    $ echo "VAR" | awk '{print $0 var1}' var1=$VAR
    VAR1000
    

    利用getline 读取行
    getline 用于读取当前的行,若在BEGIN中使用,则在主语句块中会过滤掉getline获取到的行。例如:

    $ echo -e "123\nabc\n456\ndef" | awk 'BEGIN{getline;} {print}'
    abc
    456
    def
    

    注意到在begin中我使用了getline;主语句块中print打印行,但是第一行并没有打印出来,因为在BEGIN中使用了getline这时候主语句块所读取流就不会有第一行了.所以getline用来处理表格头部信息等类似数据十分有用

    利用过滤条件进行处理 例如

    $ echo -e "123\nabc\n456\ndef" | awk 'BEGIN{getline;} NR < 3 {print}'
    abc
    

    这里通过NR (行号) 进行过滤,由于BEGIN中使用了getline因此只打印了abc

    awk 每行记录默认使用空格作为分隔符 如下:

    $ echo -e "12 3\na bc\n4 56\nd ef" | awk '{print $1}'
    12
    a
    4
    d
    

    也可以通过-F选项设置分隔符例如:

    $ echo -e "1x2\naxb\n3x4" | awk -F "x" '{print $1}'
    1
    a
    3
    

    还有第二种写法在BEGIN语句块中使用FS,如下

    $ echo -e "1x2\naxb\n3x4" | awk 'BEGIN{FS="x"} {print $1}'
    1
    a
    3
    

    在awk中使用循环进行输出 例子如下:
    准备测试文本:

    $ cat awk_loop.txt
    tw:chengdu:china
    tw:wuhai:china
    tw:xi'an:china
    $ awk 'BEGIN{FS=":"}{name[$2]=$3} END{for (i in name) {print i,name[i]}}' awk_loop.txt
    wuhai china
    xi'an china
    chengdu china
    

    以上的命令使用了关联数组以及for循环 打印测试文本

    awk内建函数一览:

    函数名 参数 描述
    length() string 返回字符串的长度
    index() string,search_string 返回search_string 在string中出现的位置
    split() string, array,delimiter 以delimiter作为分隔符将结果存入array
    substr() string, start-position,length 从start-postion截取字符串长度为length
    sub() regex,replacement,string 将regex匹配到的内容替换为replacement
    gsub() regex,replacement,string 将所有匹配到的结果替换为replacement
    match() string,regex 判断string中能否匹配到string中的任何内容,若是则返回非0 反之 返回0

    实例如下:
    split:

    $ echo -e "tw:chengdu:china" | awk 'BEGIN{FS=":"}{split($0,name,":")} END{for(i in name) {print name[i]}}'
    

    substr:

    $ echo -e "tw:chengdu:china" | awk 'BEGIN{FS=":"}{print substr($0,1,10)}'
    tw:chengdu
    

    sub:

    $ echo "tw:tw:chengdu:china" | awk 'sub(/tw/,"thoughtworks",$0)'
    thoughtworks:tw:chengdu:china
    

    gsub:

    $ echo "tw:tw:chengdu:china" | awk 'sub(/tw/,"thoughtworks",$0)'
    thoughtworks:thoughtworks:chengdu:china
    

    match

    $ echo "tw:tw:chengdu:china" | awk '{print match($0,/tw/)}'
    1
    

    这是部分常用命令总结,后面我还会总结一下其他常用命令.

    相关文章

      网友评论

          本文标题:Linux Shell脚本攻略读书笔记III —— 常用命令 I

          本文链接:https://www.haomeiwen.com/subject/rbkemftx.html