shell_advanced
1、輸入輸出,重定向,管道
2、<(cmd);>(cmd)
3、>;<;>>;<<;>>>;<<<
4、文本处理_1:cat;head;tail;cut;wc;sort;uniq;tr;tac;rev
一、輸入輸出,重定向,管道
1、Linux 程序有三个标准的输入输出,分别是:
标准输入,用数字0表示,默认连接到键盘,程序通常用来获取用户的输入
标准输出,用数字1表示,默认连接到屏幕,程序通常用来输出信息
标准错误,用数字2表示,默认连接到屏幕,程序通常用来输出错误信息
解析:
命令 passwd 从标准输入读取用户密码,所以用户可以用键盘输入密码
命令 echo 把结果输出到标准输出,所以可以在屏幕上看到结果
普通用户没有权限查看/root 目录,所以出错,于是 ls 把错误信息输出到标准错误,也就是屏幕
2、> 与 >>
> 删除原来数据,写入新数据
>> 将新数据追加到原来数据之后
3、/dev/null
俗称:垃圾桶文件
# echo hello world > /dev/null --重定向到该文件的数据都被内核丢掉了,可以用这个特性来屏蔽某些输出信息
# ls / /root 2> /dev/null --屏蔽掉命令的出错信息
4、输出重定向
用户可以根据需要,把默认的输入输出的方向进行修改
# ls -l > test
# ls -l 1> test --两条都是标准输出重定向到 test 文件,即默认1可省略
# ls /jjjj 2> test --将标准错误重定向到 test 文件
# ls / /jjjj 1> stdout 2> stderr --将标准输出与标准错误分别重定向到两个不同的文件中
# ls /jjjj / > std 2>&1 --将标准错误合并到标准输出,并重定向到一个文件当中
# ls /jjjj / &> std --结果与上条语句等价,更加简洁
# ls /jjjj / &>> std --也是将标准输出与标准错误重定向追加到一个文件
5、标准输入重定向
# cat 0< /etc/passwd
# cat < /etc/passwd
# cat /etc/passwd --cat命令的标准输入来源于文件 /etc/passwd 中
6、管道
上面所描述的重定向,是把标准的输入输出连接到文件。我们也可以把多个程序之间的标准输入输出进行连接,实现命令之间数据的传递,这种技术被形象地称做管道,程序的输出就像流水在管道中流通一样,从最左边的程序流到最右边的程序。管道是linux shell 里非常常见的技术,利用管道技术可以达到配合使用多个小工具,完成非常复杂而强大的功能。
# cat /etc/passwd | head -n 3 --左边的命令的标准输出作为右边的命令的标准输入
# cat /etc/passwd | head -n 3 | tail -n 1
7、标准输入输出的深入探讨
标准的输入输出是Linux 默认为程序创建好的三个文件描述符,虽然大多数的程序都会使用这三个文件描述符来作为自己的输入输出,但是这并非是强制性的,也就是说,程序可以不使用这三个标准的文件描述符,而是自己打开新的文件描述符来使用。当程序不使用标准的输入输出时,这里所使用的重定向对其也就不起作用了。例如:
passwd: 程序从标准输入读取用户密码,因此我们可以通过重定向标准输入来向它提供密码
ssh: 命令是用于远程登录的程序,它读取用户输入的密码时,使用的不是标准输入,因此我们不能通过重定向标准输入来向它提供密码
8、验证进程的标准输入输出所连接的文件
# sleep 999 1> /tmp/good 2>&1 --在一个终端运行命令
# pgrep -x sleep --在另外一个终端,找出sleep 的进程ID
# lsof -anop 16715 -d 0,1,2 --查看该进程所打开的文件
9、验证重定向发生的时机
# vim file
# cat -n file > file --期待cat 会在每一行前面加上行号,然后把结果重定向保存回原来的文件file 中
# cat file --为空了
原因:shell 执行命令之前,会先执行重定向操作,在第 2 条命令中,先执行 > file,这个重定向操作会把文件file 的内容清空。当重定向操作把file 文件清空之后,再cat 该文件,自然就看不到任何内容了
$ sudo ls /root > /root/ls.log --该例子中,用户没有机会输入密码,因为重定向操作先执行,当前用户是普通用户,无法在路径 /root/ls.log 中创建文件,shell 出错并退出:bash: /root/ls.log: Permission denied。此时还没有执行命令sudo,所以也就没有机会输入密码
二、<(cmd);>(cmd)
1、<(cmd)
用进程置换的方式重定向标准输入
2、>(cmd)
用进程置换的方式重定向标准输出
3、进程置换
进程的标准输出存到一个临时文件中,返回临时文件的路径 <(),当需要使用程序的输出,但是又不想生成一个中间文件时,可以考虑使用进程置换
# paste <(seq $(wc -l /etc/passwd | cut -d" " -f1)) <(awk -F: '{print $1}' /etc/passwd)
# paste <(seq 26) <(awk -F: '{print $1}' /etc/passwd) --可将该两条命令进行对比
三、>;<;>>;<<;>>>;<<<
1、> --输出重定向,创建(存在则覆盖)
# echo 'hello world' > test -- 不存在 test 则创建,存在则覆盖里面内容
2、< --输入重定向,来源于文件
# less < /etc/passwd --将 /etc/passwd 里面的内容输入到工具 less
# cat < <(ls /) --这里使用到命令置换
# wc -l < $(echo /etc/passwd)
# wc -l < <(cat /etc/passwd) --这里使用到进程置换
3、>> --重定向到文件,创建(存在则添加到文件末尾)
# echo 'hello george' >> george -- 不存在 george 则创建,存在则追加内容至文件末尾
4、<< --重定向,用于Here document
4.1、Here Document
是在Linux Shell 中的一种特殊的重定向方式,它的基本的形式如下:
cmd << delimiter
Here Document Content
delimiter
: << delimiter --shell批量注释
Here Document Content
delimiter
作用:将两个 delimiter 之间的内容(Here Document Content) 传递给 cmd 作为输入参数
4.2、终端
# cat << EOF
> one
> two
> three
> EOF
EOF --只是一个标识而已,可以替换成任意的合法字符
> --这个符号是终端产生的提示输入信息的标识符
delimiter -- 一定要顶格写,前面后面不能有任何字符,包括空格
4.3、shell
# vim here.sh --注:还可在里面使用变量
#!/bin/bash
cat << EOF > output.sh
echo "hello"
echo "world"
echo $1
EOF
# chmod a+x here.sh
# ./here.sh george
# cat output.sh --查看里面内容;在这里 $1 被展开成为了脚本的参数
注意:若不想展开这个变量,则需使用双引号将第一个 EOF 引起来。
4.4、<<-
Here Document 还有一个用法就是将 '<<' 变为 '<<-'。 使用 <<- 的唯一变化就是Here Document 的内容部分每行前面的 tab (制表符)将会被删除掉,这种用法是为了编写Here Document的时候可以将内容部分进行缩进,方便阅读代码
5、<<< --重定向,用于Here string
# wc -l <<< "$(ls -l /home)"
# while read x; do echo "hello";done <<< "$(seq 5)"
# bc <<< "2 ^ 10"
# vim string.sh
#!/bin/bash
while read line
do
if [ "${line#ftp:}" != "$line" ];then
awk -F: '{print $6}' <<< $line
break
fi
done < /etc/passwd
注释:循环读取/etc/passwd 文件中的每一行,如果是ftp 用户,就打印出其家目录,并退出循环
${line#ftp:}:某行开头匹配到了 ftp: ;则只取该行未匹配部分
# chmod a+x string.sh
# ./string.sh
四、文本处理_1:cat;head;tail;cut;wc;sort;uniq;tr;tac;rev
文本处理是每一个系统管理员都会频繁接触的任务,其核心内容是相关工具的使用,关键要点在于灵活地结合多个工具去完成任务
1、cat --concatinate,把一个或者多个文件的內容按順序連接起來,輸出到标准輸出
# cat -n /etc/passwd --显示文件内容,并且加上行号
# cat -A /etc/passwd --打印出一些不可见的字符和位置标记
# cat 1.txt 2.txt > test.txt --合并文件
2、head --读取文件头部
# head -n 3 /etc/passwd --读取文件/etc/passwd 的前面三行
# head -n -1 file --丢弃 file 的最后一行
# head -c 3 /etc/passwd --读取文件/etc/passwd 的前面三個字节
# head -c -3 file --丢弃 file 的最后 3 个字节
# head -c 10m /dev/urandom > big --创建一个10M的文件
3、tail --读取文件尾部
# tail -n 3 /etc/passwd --读取文件 /etc/passwd 后面三行
# tail -n +28 /etc/passwd --从第28行开始读取,直到文件尾部;丢弃头部的27行
# tail -c 3 /etc/passwd --读取文件 /etc/passwd 的后面三個字节
# tail -c +28 /etc/passwd --从第28字节开始读取,直到文件尾部;丢弃头部的27字节
# tail -f /etc/passwd --跟踪文件尾部内容的变化,常用來视察日志文件的变化化,非常实用
4、cut --功能类似于awk,但是没有awk那么强大和复杂,当要对数据做分列输出时,经常使用awk,用cut的时候不多
常用选项:
-d --定义分隔符
-b --输出指定位置的字节(byte)
-c --输出指定位置的字符(character)
# echo "a;b;c d;e" | cut -d ";" -f1,3,4 -- -d 定义分隔符( 默认是 TAB );-f 定义输出对应字段
# cat -n /etc/passwd | cut -d $'\n' -f1,3-5,7 -- 使用换行符做分隔符
# echo 我是中国人 | cut -b1-3 -- -b 输出指定位置的字节(byte);一个utf8 的中文字占用3个字节
# echo 我是中国人 | cut -c2-4 -- -c 输出指定位置的字符(character);与-b 的区别表现在处理非英文字符时
# echo 做个勇敢的中国人 | cut -b1-2,9 --会输出一个 ”假“ 字
# echo -n 做个勇敢的中国人 | xxd --会发现 1,2,9 这三个字节为:e581 87
# echo -n 假 | xxd --而 ”假“ 也是
5、wc --计算数据的字节数,字符数,单词数,行数
常用选项:
-c --计算字节数
-m --计算字符数
-w --计算词数
-l --计算行数
# echo -n 我是中国人 | wc -c -- -c 计算字节数,5个utf8中文占15个字节
# echo -n 我是中国人 | wc -m -- -m 计算字符数,与-c 的区别表现在处理非英文字符时,类似于命令cut
# echo -n 我是中国人 | wc -w -- -w 计算词数,没有分割符分开,5个中文算一个词,这与中文所谓的“词”是不同的
# echo -n Uppercase CHINESE | wc -w --两个词
# echo -n Uppercase CHINESE | wc -c --17个英文字节,没有 -n 就有18个(因为还有一个换行符)
# echo -n Uppercase CHINESE | wc -m --17个英文字符,没有 -n 就有18个(因为还有一个换行符)
# wc -l /etc/passwd -- -l 计算行数
6、sort --按行对文件进行排序
常用选项:
-t --指定分割符
-k --指定排序的字段
-u --去除重复的行
-n, -h --按照数值排序
-r --反过来排序
# cut -d ":" -f7 /etc/passwd | sort -u -- -u 去除重复行
# echo -e "1\n2\n10" | sort
# echo -e "1\n2\n10" | sort -n -- -n 按数值排序,不能处理K, M, G 等单位字符
# ls -lh | tail -n +2 | sort -k5,5n -- -k 指定排序的字段
# ls -lh | tail -n +2 | sort -k5,5h -- -h 按照数值排序时,能处理K, M, G 等单位字符
# head -4 /etc/passwd | sort -t: -k7,7 -- -t 以冒号 : 作为字段分割符,按第7字段排序
# head -4 /etc/passwd | sort -t: -k7,7 -k3,3n --先按第7字段排序,若第7字段有相同的,则按第3字段排序
# echo -e "1\n2\n3" | sort -nr -- -r 对排序反转
# head -4 /etc/passwd | sort -t: -k7,7 -k3,3nr --至反转第3字段排序,也可同时对两个字段反转
7、uniq --去除连续的重复行
常用选项:
-c --计算重复行的数目
# echo -e "1\n1\n2\n1" | uniq -- 结果中仍有两个1,因为这两个1是不连续的
# echo -e "1\n1\n2\n1" | sort -u -- sort 去除重复则不用连续
# cut -d: -f7 /etc/passwd | sort | uniq -c -- 在sort命令例子的基础上,计算不同的登录shell出现的次数
8、tr --转换,删除,缩减相同字符
常用选项:
-d --删除,删除匹配到的所有字母
-s --缩减,缩减相同字符
格式: tr SET1 SET2
注意: 把集合1里面的字符转换成集合2中对应位置的字符,所以原则上两个集合中的字符数目应该相同,不过,如果两个集合中的字符数不相等,程序也不会出错,请留心这种情况下的结果。要点:
a、 tr 不关心两个集合中是什么字符,它只是简单地把对应位置的字符逐个做替换而已、
b、 tr 做的是单个字符的替换,不能替换字符串
# echo abc | tr a-z A-Z --把26个小写字母转换成相对应的大写字母
# echo abc | tr ab BA --把 a 和 b,分别转换为 B 和 A
# echo 好人做好事 | tr 好 坏 -- “好” 转换为 “坏”
# echo abcdefg | tr a-z AB --集合2较短,程序自动用集合2中最后一个字符来扩展集合2
# echo abcdefg | tr a-b A-Z --集合2较长,程序自动把集合2切短
# echo Abc | tr a-zA-Z A-Za-z --实现英文字母大小反转
# echo hello world | tr -d ow -- -d 删除,匹配到的所有字母
# echo 0123456789 | tr -d 13579
# tr -d '\012' < /etc/passwd -- 删除文件/etc/passwd 中的换行符,tr 可用八进制表示一个字符
# echo aabbaacc | tr -s a -- -s,将每个连在一起的几个 a 缩减至一个
# echo aabbaacc | tr -s a A -- 集合之后再做转换
9、tac --把一个或者多个文件的內容按順序連接起來,輸出到標準輸出,每个文件中,内容按行号反序打印
# echo -e "111111111\n2222222" > f1
# echo -e "333333333\n4444444" > f2
# tac f2 f1
10、rev --把文件中的行左右反转
# echo -e "1234567\nabcdefg" > test
# rev test
五、扩展
1、cat,md5sum
# echo file1 > file1
# echo file2 > file2 --创建两个文件
# md5sum file1 file2 --对比他们的 md5 值是否相同
# head -c 10m /dev/urandom > bigfile --使用随机设备创建一个 10M 的文件
# head -c 3m bigfile > file1 --将前 3M 数据导入 file1
# tail -c 4m bigfile > file3 --将后 3M 数据导入 file3
# head -c 6m bigfile | tail -c 3m > file2 --将中间 4M 数据导入 file2
# ls -lh file*
# cat file1 file2 file3 > newbigfile --使用 cat 将三个文件合并到一个新大文件中
# md5sum newbigfile bigfile --在用命令比较旧大文件与新大文件的 md5sum 值