Shell脚本管道符与重定向

2022-09-28 20:14:35 浏览数 (1)

[TOC]

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的操作对象,和逻辑与不一样

实际案例:

代码语言:javascript复制
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中

实际示例:

代码语言:javascript复制
#语法案例
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)输入重定向

代码语言:javascript复制
#基础语法
command-line [n] <file   ##0,1,2文件描述符或&设备/dev/null

n >& m	将输出文件 m 和 n 合并
n <& m	将输入文件 m 和 n 合并

实际案例:

代码语言:javascript复制
#示例1. 和输出重定向一样,Unix 命令也可以从文件获取输入,语法为: 
$cat < catfile   #按下 [ctrl] d 离开 
testing 

#示例2.从标准输入【键盘】获得数据,然后输出给catfile文件
$cat > file

#示例3.cat 从test.sh 获得输入数据,然后输出给文件catfile
cat >catfile <test.sh

WeiyiGeek.示例2/3

代码语言:javascript复制
#示例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命令来绑定重定向;

代码语言:javascript复制
#基础语法
exec 文件描述符[n] <或> file或文件描述符或设备

实际案例:

代码语言:javascript复制
#示例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.删除文件描述符

补充知识点:

代码语言:javascript复制
#故障案例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 中的一种特殊的重定向方式,它的基本的形式如下:

代码语言:javascript复制
<< delimiter	将开始标记 delimiter 和结束标记 delimiter 之间的内容作为输入,当遇到 delimiter则结束输入

#它的作用是将两个 delimiter(分隔符号)之间的内容(document) 作为输入传递给 command.
command << delimiter
     document
delimiter

实际案例:

代码语言:javascript复制
#示例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中设置的位

代码语言:javascript复制
#基础语法
mkfifo [options] file

#选项
-m mode, --mode=mode:设置创建的FIFO的模式为 mode, 这可以是 chmod(1) 中的符号模式,并使用默认模式作为起始点,其实就是rwx权限
GNU STANDARD OPTIONS(GNU标准选项)
--help:在标准输出上打印一条用法信息,并以成功状态退出.
--version:在标准输出上打印版本信息,然后以成功状态退出.
--:终止选项列表.

实际案例:

代码语言:javascript复制
#示例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

0 人点赞