Shell脚本管道符与重定向
0x00 快速入门
主要介绍管道符与输出重定向的基础知识
1. 多命令执行
多命令顺序执行符列表:
多命令执行符 |
格式 |
作用 | |
---|---|---|---|
; |
命令1 ; 命令2 |
多个命令顺序执行,命令之间没有任何逻辑联系 |
|
&& |
命令1 && 命令2 |
逻辑与,命令1正确执行才会执行命令2,命令1不正确执行,则命令2不会执行 |
|
shift+\shift+\ =ll |
命令1 ll 命令2 |
逻辑或,当命令1执行不正确,则命令2才会执行,当命令1正确执行,则命令2不会执行。注释:其中shift+\意味着 |
例如:date ; tar -zcvf etc.tar.gz /etc ; date可以计算中间打包压缩命令执行的耗时 再如:ls && echo yes || echo no,第一个命令正确执行,输出yes,错误执行输出no
2. 管道符
命令格式: 命令1 | 命令2,有一定的编程思想在里面 命令1的正确输出作为命令2的操作对象,和逻辑与不一样
实际案例:
ls -l /etc | more #代表将ls -l /etc的输出分屏显示
netstat -an | grep ESTABLISHED #代表搜索netstat -an输出中带有ESTABLISHED的行
netstat -an | grep ESTABLISHED | wc -l #此为多管道符命令,代表到最后统计带有ESTABLISHED的行的数目,即可看出服务器上连接了多少人
3. 标准输入输出
linux启动后会默认打开3个文件描述符:
设备 |
设备文件名 |
类型 |
文件描述符 |
内存文件名 |
使用符号 |
---|---|---|---|---|---|
键盘 |
/dev/stdin |
标准输入/读取数据 |
0 |
/proc/self/fd/0 |
使用 < 或 << |
显示器 |
/dev/stdout |
标准输出数据 |
1 |
/proc/self/fd/1 |
使用 > 或 >> |
显示器 |
/dev/stderr |
标准错误输出 |
2 |
/proc/self/fd/2 |
使用 2> 或 2>> |
一条shell命令执行,都会继承父进程的文件描述符因此,所有运行的shell命令,都会有默认3个文件描述符。 即对于任何一条linux 命令执行它会是这样一个过程:
先有一个输入:输入可以从键盘,也可以从文件得到 命令执行完成:成功了就会把成功结果输出到屏幕:standard output默认是屏幕 命令执行有错误:会把错误也输出到屏幕上面:standard error默认也是指的屏幕
WeiyiGeek.标准输入输出
(1)输出重定向
类型 |
符号 |
作用 |
---|---|---|
标准输出重定向 |
命令 > 文件 |
以覆盖的方式,把命令的正确的输出,输出到指定文件或者设备中 |
标准输出重定向 |
命令 >> 文件 |
以追加的方式,把命令的正确输出,输出到指定文件或者设备之中 |
标准错误输出重定向 |
错误命令 2 > 文件 |
以覆盖的方式,把命令的错误的输出,输出到指定文件或者设备中 |
标准错误输出重定向 |
错误命令 2 >> 文件 |
以追加的方式,把命令的错误输出,输出到指定文件或者设备之中 |
(2)正确和错误输出同时保存
类型 |
符号 |
作用 |
---|---|---|
正确输出和错误输入同时保持 |
命令 > 文件 2>&1 或者 命令 &> 文件 |
以覆盖方式,把suc与err输出都保存到同一个文件中 |
命令 >> 文件 2>&1 或者 命令 &>> 文件 |
以追加方式,把suc与err输出都保存到同一个文件中+ |
|
命令 >> suc文件 2>>err文件 |
把正确的输出追加到文件1中,把错误的输出追加到文件2中 |
实际示例:
#语法案例
command-line1 [0-2] > file #0,1,2文件描述符或&设备/dev/null
&[n] 代表是已经存在的文件描述符,&1 代表输出 &2代表错误输出 &-代表关闭与它绑定的描述符
#示例1.这个例子是讲,我们执行了任意命令,并输出到/dev/sda。
#这样的话/dev/sda 里面的文件会被命令输出的内容全部替换掉,最后丢失掉其中原有的数据。
$任意命令 > /dev/sda
ifconfig > ~/desktop/test.log ##将内容保存在日志文件中
#示例2.正确输出与错误输出都显示在屏幕了,现在需要把正确输出写入suc.txt
# 1>可以省略不写,默认所至标准输出
$ls test.sh test1.sh
ls: test1.sh: 没有这个文件和目录
test.sh
#示例3.把错误输出到err.txt,正确输出到suc.txt中
$ls test.sh test1.sh 1>suc.txt 2> err.txt # 2>是将错误输出到文件
$cat suc.txt err.txt
test.sh
ls: 无法访问test1.sh: 没有那个文件或目录
# 继续追加把输出写入suc.txt err.txt “>>”追加操作符
$ls test.sh test1.sh 1>>suc.txt 2>>err.txt
#示例4.#&代表标准输出错误输出,将所有标准输出与错误输出 输入到/dev/null文件或者file.txt文件中.
$ls test.sh test1.sh &>/dev/null #及屏蔽stdout与stderr
$ls test.sh test1.sh >/dev/null 2>&1 #将错误输出2绑定给正确输出1,然后将正确输出发送给/dev/null设备这种常用
$ls test.sh test1.sh &>file.txt
#示例5.将错误输出信息关闭掉
$ls test.sh test1.sh 2>&-
test.sh
$ls test.sh test1.sh 2>/dev/null
test.sh
# 关闭所有输出
$ls test.sh test1.sh 1>&- 2>&- #关闭 1 ,2 文件描述符
注意事项:
- 特别注意错误输出大于号和文件之间不能有空格!!!
- 1、shell遇到”>”操作符,会判断右边文件是否存在,如果存在就先删除,并且创建新文件,不存在直接创建, 无论左边命令执行是否成功,右边文件都会变为空
- 2、“>>”操作符,判断右边文件,如果不存在就先创建。以添加方式打开文件,会分配一个文件描述符[不特别指定,默认为[1,2]然后,与左边的标准输出(1)或错误输出(2) 绑定
- 3、当命令:执行完,绑定文件的描述符也自动失效0,1,2又会空闲
- 4、一条命令启动,命令的输入,正确输出,错误输出,默认分别绑定0,1,2文件描述符
- 5、一条命令在执行前,先会检查输出是否正确,如果输出设备错误,将不会进行命令执行
(3)输入重定向
#基础语法
command-line [n] <file ##0,1,2文件描述符或&设备/dev/null
n >& m 将输出文件 m 和 n 合并
n <& m 将输入文件 m 和 n 合并
实际案例:
#示例1. 和输出重定向一样,Unix 命令也可以从文件获取输入,语法为:
$cat < catfile #按下 [ctrl]+d 离开
testing
#示例2.从标准输入【键盘】获得数据,然后输出给catfile文件
$cat > file
#示例3.cat 从test.sh 获得输入数据,然后输出给文件catfile
cat >catfile <test.sh
WeiyiGeek.示例2/3
#示例4.用的最多输入重定向到文件
$cat >catfile <<eof
test a file
test!
eof
##<< 这个连续两个小符号, 他代表的是『结束的输入字符』的意思。这样当空行输入eof字符,>输入多行数据后按ctrl+D结束写入
#示例5.输入重定向描述符的妙用
$wc < test.log #wc命令原本的输入是键盘,现在重新定向为文件,当然,其实不需要<
1 3 54 #行数 单词数 字节数
#下面它会要求你不断输入,知道再遇到ddy,就会停止并做相关统计,实际工作中基本不会用到.
$wc <<ddy >test.log
This is a input content;
ddy
$cat test.log
1 5 27
#还能将将字符统计的输入到Test.log中(可以无先)
补充知识点:
- EOF字符前面可以采用一个-,后面连接的EOF结束字符不用一定在首行(但是需要采用Tab键功能进行缩进)
4. exec 命令
描述:在上面讲的输入输出重定向,是将输入输出绑定文件或设备后。只对当前那条指令是有效的。如果需要在绑定之后,接下来的所有命令都支持的话,就需要用exec命令来绑定重定向;
#基础语法
exec 文件描述符[n] <或> file或文件描述符或设备
实际案例:
#示例1.将标准输出与fd 6绑定
$exec 6>&1
$ls /proc/self/fd/
0 1 2 3 6 #出现文件描述符6
#示例2.将命令标准输出绑定到suc.txt文件中(输出到该文件)
$exec 1>suc.txt
ls -al ##执行命令,发现什么都不返回了,因为标准输出已经输出到suc.txt文件了
$exec 1>&6 ##恢复标准输出
#示例3.关闭fd 6描述符
#说明:使用前先将标准输入保存到文件描述符6,文件描述符默认会打开0,1,2 还可以使用自定义描述符 。
#然后对标准输出绑定到文件,接下来所有输出都会发生到文件使用完后,恢复标准的输出,关闭打开文件描述符6。
$exec 6>&-
$ls /proc/self/fd/
0 1 2 3
#示例4.exec执行如果命令是执行一次后就退出,如果命令是一直在前台执行的情况下会持续执行;
$exec ps aux
root 84387 0.0 0.0 155372 1868 pts/0 Rs+ 09:22 0:00 ps aux
WeiyiGeek.删除文件描述符
补充知识点:
#故障案例1
可能有朋友会这样用:exec 1>suc.txt ,接下来所有输出都绑定到suc.txt 文件
exec 1>&2 #恢复采用错误输出 ,1 >& 2 意思是将标准输出重定向到句柄2错误输出
#故障案例2
#打开test.sh可读写操作与文件描述符3绑定
exec 3<>test.sh
while read line<&3
do
echo $line; #循环读取文件描述符3(读取的是test.sh内容)
done
#关闭文件的输入、输出绑定
exec 3>&-
exec 3<&-
>& 将一个句柄的输出写入到另一个句柄的输入中
<& 从一个句柄读取输入并将其写入到另一个句柄输出中
#故障案例3: 直接采用exec来进行绑定
exec<a.log
while read line
do
echo $line
done
总结重定向应用通常就以下两点:
- 1、重新设置命令的默认输入、输出,指向到自己文件(文件,文件描述符,设备其实都是文件,因为linux就是基于设备也是文件,描述符也指向是文件)
- 2、扩展自己新的描述符,对文件进行读写操作
0x02 高级管道命令
<<EOF
描述:Here Document(”嵌入文档“)是 Shell 中的一种特殊的重定向方式,它的基本的形式如下:
<< delimiter 将开始标记 delimiter 和结束标记 delimiter 之间的内容作为输入,当遇到 delimiter则结束输入
#它的作用是将两个 delimiter(分隔符号)之间的内容(document) 作为输入传递给 command.
command << delimiter
document
delimiter
实际案例:
#示例1.下面的例子,通过 wc -l 命令计算 document 的行数:
$wc -l << EOF
This is a simple lookup program
for good (and bad) restaurants 餐厅
in Cape Town.
EOF
#示例2.在shell脚本中进行使用
#!/bin/bash
cat << EOF
This is a simple lookup program
for good (and bad) restaurants
in Cape Town.
EOF
#实例3.通过管道与应用交交互
FTP_SERVER=ftp.n1.dabian.org
FTP_PATH=/debian/dists/lenny/main/installer-i386/current/images/cdrom
REMOTE_FILE=debian-cd_info.tar.gz
# -n: inhibit auto-login
ftp -n << EOF
open $FTP_SERVER
user anonymous me@linuxbox
cd $FTP_PATH
hash
get $REMOTE_FILE
bye
EOF
ls -l $REMOTE_FILE
注意:
- 开始的delimiter前后的空格会被忽略掉\
- 结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进
mkfifo 模块
mkfifo 使用指定的文件名创建FIFO(也称为”命名管道”),它是一种特殊的文件类型,它允许独立的进程通讯(反弹Shell你懂的) 一个进程打开FIFO文件进行写操作,而另一个进程对之进行读操作, 然后数据便可以如同在shell或者其它地方常见的的匿名管道一样流线执行. 默认情况下,创建的FIFO的模式为0666(‘a+rw’)减去umask中设置的位
#基础语法
mkfifo [options] file
#选项
-m mode, --mode=mode:设置创建的FIFO的模式为 mode, 这可以是 chmod(1) 中的符号模式,并使用默认模式作为起始点,其实就是rwx权限
GNU STANDARD OPTIONS(GNU标准选项)
--help:在标准输出上打印一条用法信息,并以成功状态退出.
--version:在标准输出上打印版本信息,然后以成功状态退出.
--:终止选项列表.
实际案例:
#示例1.mkfifo -m 使用案例
mkfifo -m 777 myfifo
cat /etc/passwd > myfifo & #将cat命令的输出作为此myfifo的输入,并放在后太运行、
[10] 6285
#再用cut命令从该myfifo中读出数据进行处理
cut -d: -f1-3 < myfifo
root:x:0
bin:x:1