• LinuxShell脚本笔记二


    cat
    读取多个文件
    cat file1 file2 ...
    输入信息与文件混合
    echo 'this is message'|cat - filename

    cat -s filename # 将文本中多行空白行压缩为1行
    cat filename|tr -s ' ' # 去除空白行
    cat -n filename #标记行号

    find
    find base_path
    # 列出该目录以及它的子目录的所
    # ll与ls通常只能看到本路径的文件与路径,无法看到子目录中的文件,用find解决

    根据文件名或者正则表达式进行匹配搜索
    find path -name "xxx.txt" # 根据名称进行匹配
    find path -iname "xxx.txt" # 根据名称-忽略大小写进行匹配
    find . ( -name "*.sh" -o -name "log.*" ) -print # 一次性多个条件进行匹配
    find path -path "xxx" # 将路径与文件作为一个整体进行匹配
    find path -name "code*" 与 find path -path "*code*"的区别在于前者只找文件名为code*,而后者只要路径带code即匹配成功
    find path -regex "xxxxxx" # 符合正则表达式
    find path -iregex "xxxxxx" # 忽略大小写,符合正则表达式

    以上的参数进行匹配时,可以用!表示否定。即匹配不符合该条件的内容
    find . ( ! -name "*.sh" -a ! -path "*log*" -a ! -path "*code*" )

    以上查找都是目录向下递归查找,如果子目录层级太多,可能文件会很多,查找变得没有意义。此时可以规定查找的深度
    -mindepth 表示最低多少层往下查找,-maxdepth表示最多查找多少层级

    find . -mindepth 2 -type f -print
    # type表示文件类型 f表示普通文件,d表示目录,l表示链接,c字符设备,b块设备,s套接字,p表示fifo
    shell进行匹配时会先将符合条件1的结果都找到,再匹配第二个条件,依此类推。所以-maxdepth或者-mindepth可以尽量在前,它能缩小查找范围。

    根据时间查找
    -atime 用户最近一次访问时间
    -mtime 文件内容最后一次被修改的时间
    -ctime 文件元数据
    参数以整天数给出
    find . -atime 7 # 用户访问距离现在恰好7天;+7表示超过7天,-7表示最近7天即小于7天
    -amin -mmin -cmin都表示分钟

    基于文件大小搜索
    find . -size 2k # c表示字节,w表示字即2字节,b表示块512字节,k千字节,M,G
    基于文件权限
    find . -perm 644
    基于用户名或者UID
    find . -user root # 与find . -user 0 等效

    结合find执行命令或动作 -exec,适合批量处理某些文件
    任务:将某位用户(比如root)的全部文件所有权更改为另一个用户:
    find . -type f –user root –exec chown slynux {} ; #{}与-exec结合使用 表示find到的每一个文件,后面的;是固定格式
    find . -name "*.sh" -exec chmod 774 {} ;
    find . -name "*.sh" -exec cat {} ;>./script.learn.log

    关于find命令结合-prune排除指定目录/文件的用法
    两种写法:
    find . -name "*.sh" -prune -o -type f -print
    # 注意:
    # 1.如果是-a只会输出前面的结果,即prune会返回一种表示执行失败(实际prune成功)的结果,-a后续不会执行;
    # 2.另外不加print表示整体隐形的print,输出的结果为不排除给定部分的结果输出
    find . ! ( -name "*.sh" -prune ) -type f
    # 可以加-a,也可以不加,结果相同
    # 可以加print,也可以不加,结果相同
    # 如果加-o,那么只会输出前半部分的结果,即整体(不排除指定的部分)
    ☆ 此处感觉对于单纯命令和带print命令的区别不太理解,对于这部分的实现逻辑也不清楚。

    xargs
    cat example.txt |xargs # 多行输入行尾的 被解释为一个空格,多行合为一行
    cat example.txt |xargs -n 2 # 新合成的行每行保留2个字符串,超过2个换行
    cat example.txt |xargs -d 'x' # 新合成的行以'x'作为分隔符号换行。默认情况以IFS作为输入定界符

    cat args.txt| xargs -n 1 cmd # 一个一个将args.txt中的行内容喂给cmd
    如果cmd有多个参数,例如 cmd -p args -l,可以考虑下面的写法进行替换
    cat args.txt| xargs -I {} cmd -p {} -l # 注意关键参数为大写的I

    find与xargs结合使用
    为了避免xargs误会行内容的空格为定界符,需要使用print0与find结合,以字符null作为分隔输出。
    find source_code_path -type -f -name "*.java" -print0 | xargs -0 wc -l # xargs -0将以“”作为定界符

    场景使用:
    执行一些来自stdin的多个参数的命令,可以采用子shell妙招
    cat files.txt | (while read arg; do cat $arg;done) # 管道前模拟来自stdin的多参数命令,后续子shell的用法仔细体会
    也可以尝试使用xargs来进行处理
    cat files.txt | xargs -I {} cat {}

    tr(translate)
    字符替换,删除以及压缩。一般用法为 tr [参数] set1 set2。

    将来自stdin的输入字符从set1映射到set2,并将输出写到stdout。两个映射的set为字符集。如果set1.length>set2.length,那么set2用最后一个字符不断复制达到与set1长度相同; 如果set1.length<set2.length,则set2长度超过的部分无效。

    集合的定义('起始字符-终止字符')
    'A-Z0-9' 'A-FN-X' '0-9'如果不是一个连续的字符序列,那就只包含了三个元素,等价于('起始字符' '-' '终止字符')

    可以使用一定的算法对字符替换达到加密的效果,而后再替换回来达到解密的效果
    echo 12345 | tr '0-9' '9876543210' #Encrypted
    echo 87654 | tr '9876543210' '0-9' #Decrypted
    比较出名的ROT13加密算法,加密和解密都使用同一个函数。
    echo "hello" | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' 'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm'
    # 可以试着把获得的结果使用同一个替换规则进行处理,看看结果是什么

    通过指定需要删除的字符集合,将出现在stdin中的字符进行清洗:
    cat file.txt | tr -d '0-9' #把文本中的数字全部剔除
    echo "Hello 123 world 456" | tr -d '0-9'

    补集
    场景:如果在清洗文本的时候,对于需要清洗的部分,不知道如何界定字符范围,或者界定字符范围的表达非常复杂,而同时,需要保留的字符范围很简单,可以考虑补集法。
    如:hello 1 charg2 33jdlsajkl 4AJKLDAUIOl 5.sjliil%%% 需要将数字提取出来:
    echo hello 1 charg2 33jdlsajkl 4AJKLDAUIOl 5.sjliil%%% | tr -d -c '0-9 ' # -c [set] 定义了一个补集,有时候表达起来会比较简洁

    压缩连续重复的字符 tr -s [set]
    set中的字符,只要是重复的,可以压缩为单个字符。

    一些约定的,简单的字符集表达,使用时,按照 tr [:set1:] [:set2:]的格式
    alnum: 字母和数字
    alpha: 字母
    cntrl: 控制字符(非打印字符)
    digit: 数字
    graph: 图形字符
    lower: 小写字符
    print: 可打印字符
    punct: 标点符号
    space: 空白字符
    upper: 大写字符
    xdigit: 十六进制字符
    如:tr '[:lower:]' '[:upper:]'

    md5sum/sha1sum
    md5sum file >file.md5 # 将该文件的md5结果和文件名一起存放在file.md5中,结果是一个32个字符的十六进制串
    md5sum -c file.md5 # 校验文件是否与file.md5记录的校验结果一致
    md5sum *.md5 # 校验所有的md5文件

    对一个目录中所有文件以递归的方式进行校验
    md5deep/sha1deep -rl path > direc.md5
    也可以用find+xargs的方式:
    find path -type f -print0 | xargs -0 md5sum >> direc.md5
    md5sum -c direc.md5

    排序、单一与重复
    sort可以对文本文件与stdin进行排序操作,从stdin中获取输入,将输出写入stdout。
    uniq是个经常与sort一同使用的命令,uniq可以从文本和stdin中提取不重复的行(重复的行只输出一次)。

    sort file1.txt file2.txt .. > sorted.txt # 将这些文件的内容提取并进行排序后输出到sorted.txt中
    sort file1.txt file2.txt .. -o sorted.txt # 效果相同

    cat sorted_file.txt | uniq> uniq_lines.txt # 将不重复的内容提取到文件中

    sort -n file.txt # 按照数字排序
    sort -r file.txt # 按照逆序排序
    sort -M months.txt # 按照月份排序
    sort -C sorted.txt # 查看是否已经完全排序
    如果需要检查是否用数字进行过完全排序:
    sort -nC sorted.txt

    sort -m sorted1.txt sorted2.txt

    -k 表示依据哪一列进行排序,对表单格式的文本有效果
    sort -nrk 1 data.txt # 对文本第一列按照数字逆序排列
    对于-k参数要注意,如果文本的数据是比较整齐的列,可以用此排序;如果不是,小心它对比的列到底是该行里的什么位置的字符,对于只有一列的,如果排序按照第二列排序,那么没有第二列的会被排在最靠前。

    sort -z data.txt | xargs -0 # 使sort输出 与 以‘’结尾的xargs命令相兼容

    -d指明以字典序排序
    -b忽略文件中的前导空白字符串

    uniq可以将连在一起的重复行处理为单一行,如果需要所有文本都是不重复的,需要与sort搭配使用。
    cat uniq1.txt |uniq # 只能处理连续重复的行
    sort uniq1.txt |uniq # 保证整个文本内容不重复

    uniq其它用法:
    uniq -u sorted.txt # 显示内容中没有出现重复的行
    uniq -c sorted.txt # 统计各行在文件中出现的次数
    uniq -d sorted.txt # 显示内容中重复的行
    -s 2 表示跳过前两个
    -w 2表示只取2个字符进行比较
    sort data.txt | uniq -s 2 -w 2

    将命令输出作为xargs命令输入的时候,最好为输出的各行添加一个0值字节终止符。在将uniq命令的输入作为xargs的数据源时,同样如此。例如,stdin的文本行中,This is a line 是一个单行,但是xargs会认为是4个不同的参数,但只是一个单行而已。如果使用0作为终止符,那么就被作为定界符。使用-z命令生成包含0值字节终止符的输出:
    uniq -z file.txt|xargs -0 rm

    临时文件命名与随机数
    编写脚本时临时存储的文件,最好放在/tmp,该目录下的文件会在系统重启时被清空
    如果有tempfile这个命令,可以直接用该命令生成临时文件名
    echo ${tempfile} # /tmp/fileawm8y
    如果没有安装tempfile命令,可以使用$RANDOM或者$$
    temp_file="/tmp/file-$RANDOM" #用随机数作为临时文件名后缀
    temp_file="/tmp/xxx.$$" # 用.$$作为添加的后缀,会被扩展成当前运行脚本的进程ID

    分割文件和数据
    split -b 10k data.file # 每个文件大小10k,分割这个文件。k,G,M,c(byte),w(word)
    split -b 10k datafile -d -a 4 # 分割出来的文件以数字为后缀,且数字长度为4
    split -l 10 data.file # 分割文件不以大小,而是以行数
    split [COMMAND_ARGS] prefix # 最后一个参数表示分割文件的前缀名
    split -b 10k datafile -d -a 4 splited_file # 分割的文件名都以“splited_file”打头

    csplit是split的一个变体,可以根据文本的自身特点进行分割,是否存在某个单词或者文本内容都可以作为分割条件。

    根据扩展名切分文件名
    看一个不用分割字符串,直接获取到文件的名称和后缀名的例子
    file_jpg="sample.jpg";name=${file_jpg%.*};echo file name is : $name # 获取文件名称
    file_jpg="sample.jpg";extension=${file_jpg#*.};echo extension is : $extension # 获取后缀名称
    注意%和%%的不同,前者是非贪婪操作,只要匹配成功,即将符合条件的内容输出,停止匹配;后者是贪婪操作,会一直匹配到不符合要求的内容为止:
    file_jpg="ex.sample.jpg";name=${file_jpg%.*};echo file name is : $name
    file_jpg="ex.sample.jpg";name=${file_jpg%%.*};echo file name is : $name
    ${VARxy},var表示变量名称,x表示百分或井号,y表示匹配表达式;
    百分查右,右侧完全匹配则删右;井号取左,左侧完全匹配则去左
    贪婪模式下,删除掉能够匹配的最大结果

    批量重命名和移动
    综合运用:
    #!/bin/bash
    #Filename: rename.sh
    #Description: Rename jpg and png files
    count=1;
    for img in *.jpg *.png
    do
    new=image-$count.${img##*.}
    mv "$img" "$new" 2> /dev/null
    if [ $? -eq 0 ];
    then
    echo "Renaming $img to $new"
    let count++
    fi
    done

    也可以用rename来批量操作重命名:
    rename *.JPG *.jpg
    rename 's/ /_/g' * # 将文件名中的空格替换成字符"_"
    rename 'y/A-Z/a-z/' *

    拼写检查
    /usr/share/dict/下包含了一些词典文件。可以利用这个列表来检查某个单词是否为词典中的单词。

    交互输入自动化
    场景1:如何能够把脚本运行时需要的内容提前用命令或者脚本传输送入?
    #!/bin/bash
    #Filename: interactive.sh
    read -p "Enter number:" no ;
    read -p "Enter name:" name
    echo You have entered $no, $name;
    将需要的输入用stdin的形式传入,用 表示Enter键。
    echo -e "1 hello " | ./interactive.sh # 结果:You have entered 1, hello
    或者
    ./interactive.sh < input.data

    场景2:脚本随机产生需要输入的内容,此时如何使用命令来提供脚本需要的内容?
    yum install expect

    #!/usr/bin/expect #注意这里不是/bin/bash,除了给与该脚本权限,还需要用./的方式执行,不能用sh
    #Filename: automate_expect.sh # 通过检查输入提示来发送数据
    spawn ./interactive .sh # 指定需要自动化哪一个命令
    expect "Enter name:"
    send "hello "
    expect "Enter number:"
    send "1 " # 与expect一起等待消息,发送需要输入的内容
    expect eof # 明确命令交互结束

  • 相关阅读:
    JavaScript判断图片是否加载完成的三种方式 (转)
    支付宝异步通知notify_url接收不了问题解决(转)
    支付宝接口使用文档说明 支付宝异步通知(notify_url)与return_url
    Nginx Cache中$request_filename(转)
    win7下搭建nginx+php的开发环境(转)
    Nginx报出504 Gateway Timeout错误2
    BZOJ 3990 [SDOI 2015] 排序 解题报告
    BZOJ 3992 [SDOI 2015] 序列统计 解题报告
    BZOJ 3993 [SDOI 2015] 星际战争 解题报告
    BZOJ 3971 Матрёшка 解题报告
  • 原文地址:https://www.cnblogs.com/bruceChan0018/p/14854556.html
Copyright © 2020-2023  润新知