zoukankan      html  css  js  c++  java
  • LinuxShell脚本攻略--第二章 命令之乐

    用 cat 进行拼接 
    文件查找与文件列表
    玩转 xargs 
    用 tr 进行转换
    排序
    临时文件命名与随机数
    分割文件和数据
    根据扩展名切分文件名
    mv 批量重命名文件
    交互输入自动化

    cat:

    echo 'Text through stdin' | cat - file.txt    #  - 被作为 stdin 文本的文件名。
    $ cat -s file               #压缩相邻的空白行
    $ cat -T file.py          #将制表符显示为^I
    $ cat -n lines.txt       #显示行号

    find:

    $ find . -print
    $ find .

    这两条命令效果是一样的。都是查找当前目录下的所有的文件及目录,使用-print时‘ ’作为用于输出的文件名进行分隔,-print0 指明了使用‘’ 进行分隔。

    $ find /home/slynux -name "*.txt" -print       #按文件名查找
    $ find . -iname "example*" -print              #按文件名不区分大小写查找
    $ find . ( -name "*.txt" -o -name "*.pdf" ) -print     # -o OR条件 ()将括号中的语句作为一个整体
    $ find /home/users -path "*/slynux/*" -print # -name 用给定的文件名匹配,-path将文件路径作为一个整体进行匹配。
    $ find . -regex ".*(.py|.sh)$" #正则表达式 查找.py或.sh文件
    $ find . -iregex ".*(.py|.sh)$" #不区分大小写
    $ find . ! -name "*.txt" -print # !否定。不已.txt结尾的文件
    $ find . -maxdepth 1 -name "f*" -print #基于目录的深度查找 -maxdepth -mindepth

    在有 -maxdepth 或 -mindepth时,这两个参数应该作为第三个参数出现。如果作为第4个或之后的参数,就可能会影响到 find 的效率,因为它不得不进行一些不必要的检查。例如,如果 -maxdepth 作为第四个参数, -type 作为第三个参数, find首先会找出符合 -type 的所有文件,然后在所有匹配的文件中再找出符合指定深度的那些。但是如果反过来,目录深度作为第三个参数, -type 作为第四个参数,那么 find 就能够在找到所有符合指定深度的文件后,再检查这些文件的类型,这才是最有效的搜索之道。
    -type 按类型查找

    文件类型       类型参数
    普通文件         f
    符号链接         l
    目录           d
    字符设备         c
    块设备          b
    套接字          s
    FIFO             p

    $ find . -type d -print    #列出所有的目录

    Unix/linux文件系统中每个文件都有三种时间戳:

    访问时间( -atime  ):用户最近一次访问文件的时间。
    修改时间( -mtime ):文件内容最后一次被修改的时间。
    变化时间( -ctime  ):文件元数据(例如权限或所有权)最后一次改变的时间。

    -atime 、 -mtime 、 -ctime 可作为 find 的时间选项。它们可以用整数值指定,单位是天。这些整数值通常还带有 - 或 + : - 表示小于, + 表示大于。

    $ find . -type f -atime -7 -print        #打印出在最近7天内被访问过的所有文件
    $ find . -type f -atime 7 -print #打印出恰好在7天前被访问过的所有文件
    $ find . -type f -atime +7 -print     #打印出访问时间超过7天的所有文件

    -amin (访问时间),-mmin (修改时间),-cmin (变化时间)  这些时间的计量单位是“ 分钟 ”。

    使用 -newer ,我们可以指定一个用于比较时间戳的参考文件,然后找出比参考文件更新的(更近的修改时间)所有文件

    $ find . -type f -newer file.txt -print    #找出比file.txt修改时间更近的所有文件

    基于文件大小的搜索:-size

    $  find . -type f -size +2k        # 大于2KB的文件
    • b —— 块(512字节)
    • c —— 字节。
    • w —— 字(2字节)
    • k —— 1024字节
    • M —— 1024K字节
    • G —— 1024M字节
    $ find . -type f -name "*.swp" -delete    #删除匹配的文件:
    $ find . -type f -perm 644 -print       # 打印出权限为644的文件
    $ find . -type f -user fzk -print       #打印出用户fzk拥有的文件
    # find . -type f -user root -exec chown fzk {} ;
    #找到root用户的文件,执行chown fzk {},这里{}会替换成相应的文件。如果找到1.txt,2.txt。
    它会被解析为 chown fzk test1.txt 和 chown fzk test2.txt。相当于两条命令
    想在一条命令中修改一个列表的文件,在exec中使用+来代替
    $ find . -type f -name "*.c" -exec cat {} ;>all_c_files.txt #找到所有c文件,写入到单一文件

    跳过指定的目录:

    $ find devel/source_path ( -name ".git" -prune ) -o ( -type f -print )

    以上命令打印出不包括在.git目录中的所有文件的名称(路径)。( -name ".git" -prune ) 的作用是用于进行排除,它指明了 .git目录应该被排除在外,而 ( -type f -print ) 指明了需要执行的动作。这些动作需要被放置在第二个语句块中(打印出所有文件的名称和路径)。

    xargs:

    xargs 能够处理 stdin 并将其转换为特定命令的命令行参数。 xargs 也可以将单行或多行文本输入转换成其他格式,例如单行变多行或是多行变单行。

    $ cat example.txt | xargs          #多行变单行
    1 2 3 4 5 6 $ echo
    1 2 3 4 5 6 | xargs -n 3 #单行变多行
    1 2 3
    4 5 6
    $ echo "splitXsplitXsplitXsplit" | xargs -d X -n 2
    split split
    split split
    $ find . -type f -name "*.txt" -print0 | xargs -0 rm -f

    找到所有.txt删掉。如果用这条命令 find . -type f -name "*.txt" -print | xargs rm -f 文件中的空格会当做文件的分隔符,最后不知道都会删掉什么,-print0 已字符null('')来分隔输出,xargs -0 将 作为输入定界符。

    tr:tr 可以对来自标准输入的内容进行字符替换、字符删除以及重复字符压缩。它可以将一组字符变成另一组字符,因而通常也被称为转换(translate)命令。

    $ echo "HELLO WHO IS THIS" | tr 'A-Z' 'a-z'    
    hello who is this
    $ echo "Hello 123 world 456" | tr -d '0-9'   #-d 删除字符
    Hello world
    $ echo hello 1 char 2 next 4 | tr -d -c '0-9 ' #-c 补集,删掉除了0-9 空格 换行符的其他字符,也就是只留下这些字符
    1 2 4
    $ echo "GNU   is       not UNIX. Recursive     right ?  | tr -s ' ' #删掉重复的‘ ’
    GNU is not UNIX. Recursive right ?

    排序:sort

    $ sort file1.txt file2.txt > sorted.txt
    $ sort -n file.txt                                #按照数字进行排序
    $ sort -r file.txt                                #按照逆序进行排序
    $ sort -M months.txt                       #按照月份进行排序(依照一月,二月,三月......)
    $ sort -m sorted1 sorted2              #合并两个已排序过的文件
    $ sort file1.txt file2.txt | uniq           #找出已排序文件中不重复的行

    临时文件:

    $ filename=`mktemp`   #创建了一个临时文件,并打印出存储在 $filename 中的文件名。
    $ echo $filename
    /tmp/tmp.8xvhkjF5fH
    $ dirname=`mktemp -d` #创建了一个临时目录,并打印出存储在 $dirname 中的目录名。
    $ echo $dirname
    tmp.NI8xzW7VRX
    $ tmpfile=`mktemp -u` #文件名被存储在 $tmpfile 中,但并没有创建对应的文件。
    $ echo $tmpfile
    /tmp/tmp.RsGmilRpcT
    $mktemp test.XXX      #根据模板创建临时文件名
    test.2tc

    分隔文件和数据:

    $ split -b 10k data.file -d -a 4 x
    $ ls
    data.file x0009 x0019 x0029 x0039 x0049 x0059 x0069 x0079

    上面的代码将data.file分隔成每个文件大小是10kb的若干个文件。-d是以数字为后缀(没有这个参数是字母),10k还可以用M、G、c(byte)、w(word)、l(line 行数)等。-a length指定后缀的长度。最后一个参数PREFIX,前缀,是什么字符前缀就是什么。

    假如分隔一个日志文件server.log,将日志分隔成server1.log, server2.log, server3.log

    $ cat server.log

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

    $ csplit server.log /SERVER/ -n 2 -s {*} -f server -b "%02d.log" ; rm server00.log
    $ ls
    server01.log server02.log server03.log server.log

    csplit 是 split 工具的一个变体。 split 只能够根据数据大小或行数分割文件,而 csplit可以根据文本自身的特点进行分割。

    • /SERVER/ 用来匹配某一行。/[REGEX]/ 表示文本样式。包括从当前行(第一行)直到(但不包括)包含“ SERVER ”的匹配行。
    • {*} 表示根据匹配重复执行分割,直到文件末尾为止。可以用{整数}的形式来指定分割执行的次数。

    • -s 使命令进入静默模式,不打印其他信息。
    • -n 指定分割后的文件名后缀的数字个数,例如01、02、03等
    • -f 指定分割后的文件名前缀(在上面的例子中,server就是前缀)。

    • -b 指定后缀格式。例如 %02d.log ,类似于C语言中 printf 的参数格式。在这里文件名=前缀+后缀= server + %02d.log 。

    • 因为分割后的第一个文件没有任何内容(匹配的单词就位于文件的第一行中),所以我们删除了server00.log。

    分隔字符串:

    $ file_jpg="sample.jpg"
    $ name=${file_jpg%.*}
    $ echo File name is: $name
    File name is: sample

    ${VAR%.*} 的含义如下所述:
    从 $VAR 中删除位于 % 右侧的通配符(在前例中是. * )所匹配的字符串。通配符从右向左进行匹配。
    给 VAR 赋值, VAR=sample.jpg 。那么,通配符从右向左就会匹配到.jpg,因此,从 $VAR中删除匹配结果,就会得到输出 sample

    % 属于非贪婪(non-greedy)操作。它从右到左找出匹配通配符的最短结果。还有另一个操作符 %% ,这个操作符与 % 相似,但行为模式却是贪婪的,这意味着它会匹配符合条件的最长的字符串。

    $VAR=hack.fun.book.txt
    $ echo ${VAR%.*}
    hack.fun.book
    $ echo ${VAR%%.*}
    hack

    还有一个:

    $ file_jpg="sample.jpg"
    $ extension=${file_jpg#*.}
    $ echo Extension is: $extension
    Extension is: jpg

    ${VAR#*.} 的含义如下所述:
    从 $VAR 中删除位于 # 右侧的通配符(即在前例中使用的 *. )所匹配的字符串。通配符从左向右进行匹配。## 从左向右进行贪婪匹配,并从指定变量中删除匹配结果。
    可能发现了,都是删除匹配的为什么还要有两种匹配方式,用${file_jpg%*.}不能代替${file_jpg#*.}吗?看下面

    http="www.sample.com"
    echo ${http%.com}
    echo ${http%.co}
    echo ${http%.*}
    
    echo ${http#www.}
    echo ${http#ww.}
    echo ${http#*.}
    结果:
    www.sample
    www.sample.com
    www.sample
    sample.com
    www.sample.com
    sample.com

    可以看出%只能从最右侧开始匹配,#只能从最左侧开始匹配。

    批量重命名移动的例子:运用find和上面的分隔字符串的方法

    count=1;
    for img in `find . -iname '*.png' -o -iname '*.jpg' -type f -maxdepth 1`
    do
        new=image-$count.${img##*.}
        echo "Renaming $img to $new"
        mv "$img" "$new"
        let count++
    done

    实现自动交互输入。

    首先有一个运行起来需要你输入参数的脚本interactive.sh

    #!/bin/bash
    read -p "Enter param1 :" param1;
    read -p "Enter param2 :" param2;
    echo "you entered : $param1 $param2"

    运行前手动输入$ echo -e "1 hello " | ./interactive.sh 和 从文本读取 ./interactive.sh < input.data 都可以实现。
    还有一种利用expect来实现。一般的系统中不带expect包,需要自己下载,我的系统是ubuntu14.04 ,在下载expect前需要下载tcl。ubuntu系统直接运行:

    sudo apt-get install tcl tk expect

    装好了后,建一个expect.sh脚本

    #!/usr/bin/expect
    spawn ./interactice.sh
    expect "Enter param1 :"
    send "1
    "
    expect "Enter param2 :"
    send "2
    "
    expect eof
    输出:
    spawn ./interactive.sh
    Enter param1 :1
    Enter param2 :2
    you entered : 1 2
    
    

    spwan:指定那个命令需要自动化。expect:提供需要等待的消息。send:等待的消息到达后向终端发送消息。expect eof:命令交互结束。

  • 相关阅读:
    快速排序
    冒泡排序算法
    设计模式之工厂方法模式
    调用存储过程修改
    取出字符串中的回车空格
    调用存储过程实例
    C++左值
    cocos2d-x 不规则形状按钮的点击判定
    C/C++
    字符函数库 cctype
  • 原文地址:https://www.cnblogs.com/badboyf/p/6141020.html
Copyright © 2011-2022 走看看