Linux Shell脚本攻略2:命令之乐(1)

版权声明:原创文章,未经允许不得转载。www.data-insights.cn. https://blog.csdn.net/qixizhuang/article/details/77923072

用cat进行拼接


  1. cat(concatenate)是命令行玩家首先必须学习的命令之一,它通常用于读取、显示或拼接文件内容,不过cat的能力远不止如此,它甚至可以一次性将来自stdin和文件的内容拼接到一起。
    • $ cat file1 file2 file3 ... #将多个文件内容拼接在一起
  2. cat不仅可以读取文件、拼接数据,还能够从标准输入中进行读取,从标准输入中读取需要使用管道操作符。
    • $ OUTPUT_FROM_SOME COMMANDS | cat
  3. 我们可以用cat将来自输入文件的内容与标准输入拼接在一起,将stdin和另一个文件中的数据结合起来。
    • $ echo 'Text through stdin' | cat - file.txt # - 被作为stdin文本的文件名
  4. $ cat -s file # 删除额外的空白行(相邻的多个空白行只保留一个)。
  5. $ cat -T file.py # 将制表符显示为^|。
  6. $ cat -n lines.txt # 显示行号(包括空白行,如果想跳过空白行,可以使用选项-b)。

录制并回放终端会话


# -t选项用于将时序数据导入stderr,2>用于将stderr重定向到timing.log,时序信息记录了每个命令在何时运行;output.session文件用于存储命令输出。 
script -t 2> timing.log -a output.session
type commands;
'''
..
exit

# scriptreplay用于回放,按播放命令序列输出
scriptreplay timing.log output.session

文件查找与文件列表


  1. find是Unix/Linux命令行工具箱中最棒的工具之一。其工作方式为:沿着文件层次结构向下遍历,匹配符合条件的文件,执行相应的操作。
  2. $ find bash_path #列出当前目录及子目录下所有的文件和文件夹
    • 如:$find . -print # .指定当前目录,..指定父目录。-print指明打印出匹配文件的文件名(路径)。当使用-print时,\n作为用于对输出的文件名进行分隔。就算忽略-print,find命令仍会打印出文件名。
    • -print0指明使用\0作为匹配的文件名之间的定界符。当文件名中包含换行符时,这个方法就有用武之地了。
  3. 根据文件名或正则表达式进行搜索
    • $ find /home/slynux -name "*.txt" -print #选项-name的参数制定了文件名所必须匹配的字符串,我们可以将通配符作为参数使用。
    • $ find . -iname "example*" -print #选项-iname的作用和-name类似,只不过在匹配名字时会忽略大小写。
    • $ find . \( -name "*.txt" -o -name "*.pdf" \) -print #匹配多个条件
    • $ find /home/users -path "*/slynux/*" -print #选项-path的参数可以使用通配符来匹配文件路径。-name总是用给定的文件名进行匹配,-path则将文件路径作为一个整体进行匹配。
    • $ find . -regex ".*\(\.py|\.sh\)$" # 基于正则表达式来匹配文件路径
    • $ find . -iregex ".*\(\.py|\.sh\)$" # 忽略大小写。
  4. 否定参数。find也可以用!否定参数的含义,如:
    • $ find . ! -name "*.txt" -print #匹配所有不以.txt结尾的文件名。
  5. 基于目录深度的搜索。find命令在使用时会遍历所有的子目录,我们可以采用深度选项-maxdepth-mindepth来限制find命令遍历的目录深度。
    • 大多数情况下,我们只需要在当前目录中进行搜索,无须再继续向下查找。如果只允许find在当前目录中查找,深度可以设置为1;当需要向下两级时,深度可以设置为2;依此类推。
    • $ find . -maxdepth 1 -name "f*" -print #只搜索当前目录
    • $ find . -mindepth 2 -name "f*" -print #从第二级目录开始搜索
  6. 根据文件类型搜索
    • $ find . -type d -print #只列出所有的目录
    • $ find . -type f -print #只列出普通文件
    • $ find . -type l -print #只列出符号链接
    • $ find . -type c -print #只列出字符设备
    • $ find . -type b -print #只列出块设备
    • $ find . -type s -print #只列出套接字
    • $ find . -type p -print #只列出FIFO
  7. 根据文件时间进行搜索
    • 按天:访问时间-atime;修改时间-mtime;变化时间-ctime
    • 按分钟:访问时间-amin;修改时间-mmin;变化时间-cmin
    • $ find . -type f -atime 7 -print #打印出恰好在7天前被访问过的所有文件
    • $ find . -type f -atime -7 -print #打印出在最近7天内被访问过的所有文件
    • $ find . -type f -atime +7 -print #打印出访问时间超过7天的所有文件
    • $ find . -type f -amin +7 -print #打印出访问时间超过7分钟的所有文件
    • $ find . -type f -newer file.txt -print #打印出比file.txt修改时间更近的所有文件
  8. 基于文件大小的搜索
    • $ find . -type f -size +2k #大于2KB的文件
    • $ find . -type f -size -2k #小于2KB的文件
    • $ find . -type f -size 2k #大小等于2KB的文件
    • 除了k之外,还可以用其他文件大小单元。
      • b —— 块(512字节)
      • c —— 字节
      • w —— 字(2字节)
      • k —— 1024字节
      • M —— 1024K字节
      • G —— 1024M字节
  9. 删除匹配的文件
    • $ find . -type f -name "*.swp" -delete
  10. 基于文件权限和所有权的匹配
    • $ find . -type f -perm 644 -print #打印出权限为644的文件
    • $ find . -type f ! -perm 644 -print #打印出权限没有设置为644的文件
    • $ find . -type f -user slynux -print #打印出用户slynux拥有的所有文件
  11. 利用find执行命令或动作
    • find命令可以借助选项-exec与其他命令进行结合,-exec算的上是find最强大的特性之一。
    • $ find . -type f -user root -exec chown slynux {} \; #{}是一个与-exec选项搭配使用的特殊字符串。对于每一个匹配的文件,{}会被替换成相应的文件名。
    • $ find . -type f -name "*.c" -exec cat {} \;>all_c_file.txt #将给定目录中所有C程序文件拼接起来写入单个文件
    • $ find . -type f -mtime +10 -name "*.txt" -exec cp {} OLD \; #将10天前的txt文件复制到OLD目录中。
    • $ find . -type f -name "*.txt" -exec printf "Text file: %s\n" {} \; #-exec可以同printf结合来生成有用的输出信息。
    • -exec无法结合多个命令,但是我们可以将多个命令写到一个shell脚本中(如command.sh),然后在-exec中使用这个脚本:-exec ./command.sh {} \;
  12. 让find跳过特定的目录。在搜索目录并执行某些操作时,有时为了提高性能,需要跳过一些子目录。
    • $ find devel/source_path \( -name ".git" -prune \) -o \( -type f-print \) #打印出不包括在.git目录中的所有文件的名称。

玩转xargs


  1. 我们可以用管道将一个命令的stdout重定向到另一个命令的stdin,如:cat foo.txt | grep "test"。但是有些命令只能以命令行参数的形式接收数据,无法通过stdin接受数据流。
  2. 我们可以使用xargs将标准输入数据转换为命令行参数;xargs也可以将单行或多行文本输入转换成其他格式,例如单行变多行或是多行变单行。
  3. xargs命令应该紧跟在管道操作符之后,以标准输入作为主要的源数据流。它使用stdin并通过提供命令行参数来执行其他命令。如:command | xargs
  4. $ cat example.txt | xargs #单行输出
  5. $ cat example.txt | xargs -n 3 #每行最多3个参数,多行输出,参数间由空格隔开。
  6. $ echo "splitXsplitXsplitXsplit" | xargs -d X #用-d选项为输入指定一个定制的定界符。
  7. $ echo "splitXsplitXsplitXsplit" | xargs -d X -n 2 #结合-d-n选项。
  8. 读取stdin,将格式化参数传递给命令。

    
    #!/bin/bash
    
    
    # 文件名:cecho.sh
    
    echo $*'#'
    • 有一个包含着参数列表的文件(每行一个参数),通过两种方法传递给一个命令(cecho.sh),第一种方法,每次提供一个参数,如:

      ./cecho.sh arg1
      ./cecho.sh arg2
      ./cecho.sh arg3

      我们可以这样写:$ cat args.txt | xargs -n 1 ./cecho.sh

    • 第二种方法,一次性提供所有参数,如:

      ./cecho.sh arg1 arg2 arg3

    • 有时我们还需要一些固定不变的命令参数,如:

      ./cecho.sh -p arg1 -l

      xargs有一个选项-I,可以提供上面这种形式的命令执行序列。我们可以通过-I指定替换字符串,这个字符串在xargs扩展时会被替换掉,如果将-I与xargs 结合使用,对于每个参数,命令都会被执行一次。如:
      $ cat args.txt | xargs -I {} ./cecho.sh -p {} -l

  9. 结合find使用xargs。xargs和find是一对死党,但是人们通常却是以一种错误的组合方式使用他们。 如:

    $ find . -type f -name "*.txt" -print | xargs rm -f

    这种做法很危险,因为我们无法预测分隔find命令输出结果的定界符究竟是什么(\n或者),很多文件名可能包含空格,因此xargs可能会误认为它们是定界符,如hell text.txt会被xargs误解为hell和text.txt。

    只要我们把find的输出作为xargs的输入,就必须将-print0与find结合使用,以字符null(\0)来分隔输出。

    $ find . -type f -name "*.txt" -print0 | xargs -0 rm -f #xargs -0\0作为输入定界符。

  10. 统计源代码目录中所有C程序文件的行数。

    $ find source_code_dir_path -type f -name "*.c" -print0 | xargs -0 wc -l

  11. 结合stdin,巧妙运用while语句和子shell。xargs只能以有限的几种方式来提供参数,而且它也不能为多组命令提供参数,要执行包含来自标准输入的多个参数的命令,有一种非常灵活的方法。包含while循环的子shell可以用来读取参数,然后通过一种巧妙的方式执行命令:

    $ cat files.txt | ( while read arg; do cat $arg; done )

    等同于

    $ cat files.txt | xargs -I {} cat {}

    在while循环中,我们可以将cat $arg替换成任意数量的命令,这样我们就可以对同一个参数执行多条命令。也可以不借助管道,将输出传递给其他命令。这个技巧能够使用于各种问题场景,子shell操作符内部的多个命令可以作为一个整体来运行。

    $ cmd0 | ( cmd1;cmd2;cmd3 ) | cmd4

猜你喜欢

转载自blog.csdn.net/qixizhuang/article/details/77923072
今日推荐