linux shell攻略学习笔记二
1.Cat命令
这么多命令,常用的
Cat –n file 显示文件以及行数
Cat -
echo 'Text through stdin' | cat - file.txt
Text through stdin
this is file and test #这个是file.txt的内容,而 –就是echo打印出管道符接的stdin。
2.录制并回放终端会话
利用script和scriptreplay命令
录制
$ script -t 2> timing.log -a output.session type commands; … .. exit
两个配置文件被当做script命令的参数。其中一个文件(timing.log)用于存储时序信息,
描述每一个命令在何时运行;另一个文件(output.session)用于存储命令输出。
-t 选项用于将时序数据导入stderr。
2> 则用于将stderr重定向到timing.log。
回放
利用这两个文件:timing.log(存储时序信息)和output.session(存储命令输出信息),我们
可以按照下面的方法回放命令执行过程:
$ scriptreplay timing.log output.session
# 按播放命令序列输出
3.Find查找
1.用正则查找文件
–name -iname(忽略大小写) find /home/slynux -name "*.txt" –print find . -iname "example*" -print
多个条件查找
find . \( -name "*.txt" -o -name "*.pdf" \) -print
按路径匹配
find /home/users -path "*/slynux/*" -print
直接用正则
find . -regex ".*\(\.py\|\.sh\)$" find . -iregex ".*\(\.py\|\.sh\)$"
2.否定!
find . ! -name "*.txt" -print
3.于目录深度的搜索
find . -maxdepth 1 -name "f*" –print #最大深度 find . -mindepth 2 -name "f*" –print #最小深度
4.根据文件类型搜索
Unix类系统将一切都视为文件。文件具有不同的类型,例如普通文件、目录、字符设备、块 设备、符号链接、硬链接、套接字以及FIFO等。 find . -type d –print #找目录 find . -type f –print #找文件
5.根据文件时间进行搜索
这个感觉很少用到 单位是天 访问时间(-atime):用户最近一次访问文件的时间。 修改时间(-mtime):文件内容最后一次被修改的时间。 变化时间(-ctime):文件元数据(例如权限或所有权)最后一次改变的时间。 这些整数值通常还带有 - 或 + :- 表示小于,+ 表示大于。
打印出在最近7天内被访问过的所有文件:
find . -type f -atime -7 -print
打印出恰好在7天前被访问过的所有文件:
find . -type f -atime 7 -print
以分钟作为计量单位
-amin(访问时间); -mmin(修改时间); -cmin(变化时间)。
打印出访问时间超过7分钟的所有文件:
find . -type f -amin +7 -print
find另一个漂亮的特性是 -newer参数。使用 -newer,我们可以指定一个用于比较时间戳 的参考文件,然后找出比参考文件更新的(更近的修改时间)所有文件
找出比file.txt修改时间更近的所有文件
find . -type f -newer file.txt -print
6.基于文件大小的搜索
find . -type f -size +2k #大于2KB的文件 小于2k用- 等于不用+- 除了k之外,还可以用其他文件大小单元。 b —— 块(512字节)。 c —— 字节。 w —— 字(2字节)。 k —— 1024字节。 M —— 1024K字节。 G —— 1024M字节。
7. 删除匹配的文件
删除当前目录下所有的 .swp文件:
$ find . -type f -name "*.swp" -delete
8. 基于文件权限和所有权的匹配
find . -type f -perm 644 -print
# 打印出权限为644的文件
用途:找出那些没有设置好执行权限的PHP文件
9. 利用find执行命令或动作(厉害了)
find命令可以借助选项-exec与其他命名进行结合。
场景:用 -user找出root拥有的所有文件,然后用-exec更改所有权。
find . -type f -user root -exec chown slynux {} \;
在这个命令中,({}其实就是类似查找出的文件的引用)
{}是一个与 -exec选项搭配使用的特殊字符串。对于每一个匹配的文件,{}会被替换成相应的文件名。例如,find命令找到两个文件test1.txt和test2.txt,其所有者均为slynux,那么find就会执行:chown slynux {}
它会被解析为chown slynux test1.txt和chown slynux test2.txt。
\; 通过转义的分号结束
find . -type f -name "*.c" -exec cat {} \;>all_c_files.txt #cat文件追加到all_file.txt
将10天前的 .txt文件复制到OLD目录中
find . -type f -mtime +10 -name "*.txt" -exec cp {} OLD \;
-exec结合多个命令
默认-exec执行的是单个命令,把多个命令写到一个shell脚本中(例如command.sh),然
后在-exec中使用这个脚本:
-exec ./commands.sh {} \;
Print0
find . -type f -name "*.a" -print ./a.a ./b.a find . -type f -name "*.a" -print0 ./a.a./b.a
4.xargs
xargs命令应该紧跟在管道操作符之后,以标准输入作为主要的源数据流。
command | xargs
样例文件
$ cat example.txt # 样例文件 1 2 3 4 5 6 7 8 9 10 11 12
转单行
这里默认定界符为$IFS (换行/制表符/空格)
$ cat example.txt | xargs 输出:1 2 3 4 5 6 7 8 9 10 11 12
转多行
$ cat example.txt | xargs -n 3 1 2 3 4 5 6 7 8 9 10 11 12
自定义定界符
通过参数 –d指定定界符
$ echo "splitXsplitXsplitXsplit" | xargs -d X split split split split
-d –n可以一起用
$ echo "splitXsplitXsplitXsplit" | xargs -d X -n 2 split split split split
一次传多个参数
--------样例sh脚本 #!/bin/bash #文件名: cecho.sh echo $*'#' --------样例测试文件 $ cat args.txt arg1 arg2 arg3
1.调用三次脚本
$ cat args.txt | xargs -n 1 ./cecho.sh arg1 # arg2 # arg3 #
2.三个参数一次传入
$ cat args.txt | xargs ./cecho.sh arg1 arg2 arg3 #
3.简化重复参数的脚本
./cecho.sh -p arg1 -l ./cecho.sh -p arg2 -l ./cecho.sh -p arg3 -l
简化后
$ cat args.txt | xargs -I {} ./cecho.sh -p {} -l -p arg1 -l # -p arg2 -l # -p arg3 -l #
xargs有一个选项-I,可以提供上面这种形式的命令执行序列。我们可以用-I指定替换字符
串,这个字符串在xargs扩展时会被替换掉。如果将-I与xargs结合使用,对于每一个参数,命
令都会被执行一次。
-I {} 指定了替换字符串。
xargs -0指定null为定界符
场景:xargs的输入和输出只能是stdin和stdout
很多文件名中都可能会包含空格符(' '),因此xargs 很可能会误认为它们是定界符(例如,hell text.txt会被xargs误解为hell和text.txt)就必须将 -print0与find结合使用,以字符null ('\0')来分隔输出。
用法:
只要我们把find的输出作为xargs的输入,就必须将 -print0与find结合使用,以字符null ('\0')也就是xargs -0来分隔输出。
find . -type f -name "*.a" -print | xargs wc –l
优化后:
find . -type f -name "*.a" -print0 | xargs -0 wc -l
print0 是将查找结果“扁平化”放到一行,而xargs -0会用空格分割打印出各个文件。
find ./ -name "*.sh" -print0 |xargs -0 ./test1.sh ./test02.sh ./testlog.sh ./pass.sh ./fun.sh
补充场景:
一个文件要根据不同参数,运行同一个脚本
$ cat args.txt arg1 arg2 arg3
脚本内容:
#!/bin/bash #文件名: cecho.sh echo $*'#'
普通人调用:
./cecho.sh arg1 ./cecho.sh arg2 ./cecho.sh arg3
有了xargs后:
cat args.txt | xargs -n 1 ./cecho.sh arg1 # arg2 # arg3 #
还有个厉害的
$ cat args.txt | xargs -I {} ./cecho.sh -p {} -l -p arg1 -l # -p arg2 -l # -p arg3 -l #
其中 –p 变量 -l 里-p是不变的,-l也是不变的。
xargs有一个选项-I,可以提供上面这种形式的命令执行序列。我们可以用-I指定替换字符
串,这个字符串在xargs扩展时会被替换掉。如果将-I与xargs结合使用,对于每一个参数,命
令都会被执行一次。
还可以这样:
$ cat files.txt | ( while read arg; do cat $arg; done ) # 等同于cat files.txt | xargs -I {} cat {}
5.tr 转换
tr只能通过stdin(标准输入),而无法通过命令行参数来接受输入
tr [options] set1 set2
set1和set2代表集合 'A-Z' 和 'a-z'都是集合。
'ABD-}'、'aA.,'、'a-ce-x'以及'a-c0-9'等均是合法的集合。
就是替换set1的内容为ste2的内容,set1到set2是严格映射,如hashmap,set1是map的key,set2是map的val。
echo "HELLO WHO IS THIS" | tr 'A-Z' 'a-z'
用途1:加解密
$ echo 12345 | tr '0-9' '9876543210'
87654 # 已加密
$ echo 87654 | tr '9876543210' '0-9'
12345 # 已解密
用途2:删除字符
tr有一个选项-d,可以通过指定需要被删除的字符集合,
$ echo "Hello 123 world 456" | tr -d '0-9'
Hello world
# 将stdin中的数字删除并打印出来
补集-c
补集就是取反。
$ echo hello 1 char 2 next 4 | tr -d -c '0-9 \n'
1 2 4
通途3:删除重复
Tr –s 删除重复 下面是删除重复的空格
$ echo "GNU is not UNIX. Recursive right ?" | tr -s ' '
GNU is not UNIX. Recursive right ?
其他关键字
比如小写换大写:
echo "hello word"|tr '[:lower:]' '[:upper:]'
HELLO WORD
6.校验和
用途:Src源有文件盒MD5文件,下载目标下载文件后,用下载的md5校验文件。
用途2:MD5用来判定2个文件是否是同一个文件。
Md5
$ md5sum filename
68b329da9893e34099c7d8ad5cb9c940 filename
$ md5sum file1 file2 file3 ..
当使用多个文件时,输出中会在每行中包含单个文件的校验和:
[checksum1] file1
[checksum1] file2
[checksum1] file3
校验
如果需要用所有的.md5信息来检查所有的文件,可以使用:
$ md5sum -c *.md5
SAH-1
Sha-1和MD5类似,注意2点
- 命令变为sha1sum
- .md5文件变为.sha1。如file_sum.md5改为file_sum.sha1
加密工具与散列
感觉没啥用,不写了。
md5sum和SHA-1已不再安全。因为计算能力 的攀升使其变得容易被破解。推荐使用bcrypt或sha512sum这 类工具进行加密
8.排序、唯一与重复
排序
sort命令既可以从特定的文件,也可以从stdin中获取输入,并将输出写入stdout。uniq 的工作方式和sort一样。
(2) -n按照数字顺序进行排序:
$ sort -n file.txt
(3) -r按照逆序进行排序:
$ sort -r file.txt
(4) 按照月份进行排序(依照一月,二月,三月……):
$ sort -M months.txt
(5) 合并两个已排序过的文件:
$ sort -m sorted1 sorted2
(6) -k指定了排序应该按照哪一个键(key)来进行。
样例文件
$ cat data.txt 1 mac 2000 2 winxp 4000 3 bsd 1000 4 linux 1000
# 依据第1列,以逆序形式排序
$ sort -nrk 1 data.txt 4 linux 1000 3 bsd 1000 2 winxp 4000 1 mac 2000 # -nr表明按照数字,采用逆序形式排序
# 依据第2列进行排序
$ sort -k 2 data.txt 3 bsd 1000 4 linux 1000 1 mac 2000 2 winxp 4000
指定多列排序
$ cat data.txt 1010hellothis 2189ababbba 7464dfddfdfd $ sort -nk 2,3 data.txt
起止位置是2和3,就是group by sort 第二列和第三列;不需要做切割什么的了
uniq
uniq只能作用于排过序的数据输入,因此,uniq要么使用管道,要么将排过序的文件作为
输入,与sort命令结合使用。
样例文件
$ cat sorted.txt bash foss hack hack
去重
$ sort unsorted.txt | uniq
-u找出不重复,唯一的行。
$ sort unsorted.txt | uniq -u bash foss
-c显示重复次数
$ sort unsorted.txt | uniq -c 1 bash 1 foss 2 hack
-d找出重复的行
$ sort unsorted.txt | uniq -d hack
-s 指定可以跳过前n个字符;
-w 指定用于比较的最大字符数。
9.分割文件和
$ split -b 10k data.file -d -a 4
-b 除了k(KB)后缀,我们还可以使用M(MB)、G(GB)、c(byte)、w(word)等后缀
-d 以数字为后缀,可以另外使用-d参数
-a length可以指定后缀长度
-l, --lines=NUMBER put NUMBER lines per output file按行切割。
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,这些文件的内容分别
取自原文件中不同的SERVER部分。那么,可以使用下面的方法来实现:
$ csplit server.log /SERVER/ -n 2 -s {*} -f server -b "%02d.log" ; rm server00.log $ ls server01.log server02.log server03.log server.log
有关这个命令的详细说明如下。
- /SERVER/ 用来匹配某一行,分割过程即从此处开始。
- /[REGEX]/ 表示文本样式。包括从当前行(第一行)直到(但不包括)包含“SERVER”
- 的匹配行。
- {*} 表示根据匹配重复执行分割,直到文件末尾为止。可以用{整数}的形式来指定分割执
- 行的次数。
- -s 使命令进入静默模式,不打印其他信息。
- -n 指定分割后的文件名后缀的数字个数,例如01、02、03等。
- -f 指定分割后的文件名前缀(在上面的例子中,server就是前缀)。
- -b 指定后缀格式。例如%02d.log,类似于C语言中printf的参数格式。在这里文件名=前缀+后缀=server + %02d.log。
因为分割后的第一个文件没有任何内容(匹配的单词就位于文件的第一行中),所以我们删
除了server00.log。
根据扩展名切分文件名
借助%操作符可以轻松将名称部分从“名称.扩展名”这种格式中提取出来。你可以按照下面
的方法从sample.jpg中提取名称。
file_jpg="sample.jpg" name=${file_jpg%.*} echo File name is: $name
输出结果:
File name is: sample
下一个任务是将文件名的扩展名部分提取出来,这可以借助 # 操作符实现。
提取文件名中的 .jpg并存储到变量file_jpg中:
extension=${file_jpg#*.} echo Extension is: jpg #输出结果: Extension is: jpg
10.交互输入自动化
echo –e实现
样例脚本
#!/bin/bash #文件名: interactive.sh read -p "Enter number:" no ; read -p "Enter name:" name echo You have entered $no, $name; $ echo -e "1\nhello\n" | ./interactive.sh You have entered 1, hello
我们用echo -e来生成输入序列,-e表明echo会解释转义序列
Expect实现
在默认情况下,多数常见的Linux发行版中并不包含expect
自动化脚本
#!/usr/bin/expect #文件名: automate_expect.sh spawn ./interactive.sh expect "Enter number:" send "1\n" expect "Enter name:" send "hello\n" expect eof
运行结果如下:
$ ./automate_expect.sh
解释脚本:
Spawn 参数指定需要自动化哪一个命令;
Expect 参数提供需要等待的消息;
Send 是要发送的消息;
expect eof 指明命令交互结束。
11. &并行进程
我们利用了Bash的操作符&,它使得shell将命令置于后台并继续执行脚本。这意味着一旦循环结束,脚本就会退出,而md5sum命令仍在后台运行。
为了避免这种情况,我们使用$!来获得进程的PID,在Bash中,$!保存着最近一个后台进程的PID。我们将这些PID放入数组,然后使用wait命令等待这些进程结束。