Linux shell编程之输入输出重定向上篇

使用重定向我们可以将程序输入和输出定向到指定的位置,而不仅仅只是显示在屏幕上。在学习重定向之前,先要学习Linux 标准文件描述符。
一、标准文件描述符
Linux系统将每个对象当作文件处理,包括输入输出,Linux使用文件描述符标识每个文件对象,文件描述符是一个非负整数,可以唯一地标识会话中打开的文件,每个进程最多可以有9个打开文件的描述符,bash shell为特殊需要保留了前3个文件描述符(0、1、2),
0 标准输入 stdin
1 标准输出 stdout
2 标准错误 stderr
bash shell使用这3个文件描述符将输入输出定向到相应位置。
1.1 stdin
shell通过stdin文件描述符从标准输入(通常指键盘)接受输入,使用输入重定向符号’<’可以用其它文件流替换标准输入流,这样shell从文件流中获取输入,就像从标准输入获取数据一样。一些针对文件的shell命令如果没有指定文件,会从stdin中读取数据:

$ cat 
hello
hello
world
world
^C

利用输入重定向将cat的输入重定向到文件:

$ cat test.txt 
i have an apple
i have a  pen
$ cat < test.txt 
i have an apple
i have a  pen

1.2 stdout
shell通过stdout文件描述符向标准输出(通常指屏幕)输出数据,使用输出重定向符号’>’可以将标准输出流重定向。

$ cat test.txt 
i have an apple
i have a  pen
$ ls -l > test.txt 
$ cat test.txt 
total 8
-rw-r--r-- 1 root root 22 Feb 25 17:37 sed.txt
-rwxrw-r-- 1     30 Feb 28 06:42 test
-rw-r--r-- 1      0 Mar 17 16:45 test.txt

‘>’会覆盖原有文件中的数据,使用’>>’可以向文件末尾追加。

$ date >> test.txt 
$ cat test.txt 
total 8
-rw-r--r-- 1 root root 22 Feb 25 17:37 sed.txt
-rwxrw-r-- 1     30 Feb 28 06:42 test
-rw-r--r-- 1      0 Mar 17 16:49 test.txt
Fri Mar 17 16:49:22 PDT 2017

1.3 stderr
stderr为标准错误输入描述符,默认情况下stderr与stdout指向相同的位置,我们看到的效果就是stderr的输出显示在屏幕上,与stdout完全相同。

$ ls -l xxxxxxx > test.txt 
ls: cannot access 'xxxxxxx': No such file or directory
$ cat test.txt 
$ 

我们利用’>’重定向了stdout(ls -l命令出错,stdout输出空,重定向到文件的效果就是清空文件),但是stderr不会被一起重定向,shell会将stdout与stderr的输出分开处理。
二、重定向stderr
通过 “2>” 可以重定向stderr:

$ ls -l xxxxxxx 2> test.txt 
$ cat test.txt 
ls: cannot access 'xxxxxxx': No such file or directory

同样执行这个命令,错误信息不会再显示到屏幕。如果命令的输出中既有stdout又有stderr,我们将stderr重定向到文件,stdout仍然会显示到屏幕。

$ ls -l xxxxxxx sed.txt 2> test.txt 
-rw-r--r-- 1 root root 22 Feb 25 17:37 sed.txt
$ cat test.txt 
ls: cannot access 'xxxxxxx': No such file or directory

也可以同时重定向stdout和stderr:

$ ls -l xxxxxxx sed.txt 2> stderr.txt 1> stdout.txt 
$ cat stderr.txt 
ls: cannot access 'xxxxxxx': No such file or directory
$ cat stdout.txt 
-rw-r--r-- 1 root root 22 Feb 25 17:37 sed.txt

shell还提供了一个特殊的重定向符号”&>”,使用”&>”可以将stdout和stderr一起重定向。

$ ls -l xxxxxxx sed.txt &> test.txt 
$ cat test.txt 
ls: cannot access 'xxxxxxx': No such file or directory
-rw-r--r-- 1 root root 22 Feb 25 17:37 sed.txt

三、在脚本中重定向输出
如果想在脚本中生成错误信息,可以将单个输出行重定向到stderr,只需将stdout定向到stderr,重定向到某个文件描述符时,必须在文件描述符前面添加’&’。

$ cat test.sh
#!/bin/bash
echo "this is stderr" >&2
echo "this is stdout."
$ ./test.sh
this is stderr
this is stdout.
$ ./test.sh 2> stderr.txt 
this is stdout.
$ cat stderr.txt 
this is stderr

将错误消息与标准输出分开是shell脚本编程的一个基本原则。如果有脚本中需要重定向大量数据,使用echo语句一行一行定向就太不方便了。可以使用exec命令将脚本执行期间的输出重定向到特定的文件描述符:

$ cat test.sh
#!/bin/bash
exec 1> testout
exec 2> testerr
echo "this is first stdout" 
echo "this is second stdout"
echo "this is first stderr" >&2
echo "this is second stderr" >&2
$ ./test.sh
$ cat testout 
this is first stdout
this is second stdout
$ cat testerr 
this is first stderr
this is second stderr

四、在脚本中重定向输入
使用exec命令同样可以重定向stdin。

exec 0> testfile

这条命令告知shell它应该从文件testfile中获取输入,而不是等待stdin的输入。

$ cat testfile
total 36
drwxr-xr-x 2     4096 Mar 18 05:15 ./
drwxr-xr-x 4 root root 4096 Mar 14 06:00 ../
-rw-r--r-- 1 root root   22 Feb 25 17:37 sed.txt
-rw-rw-r-- 1       15 Mar 17 17:23 stderr.txt
-rw-rw-r-- 1       47 Mar 17 17:07 stdout.txt
-rw-rw-r-- 1       43 Mar 18 05:03 testerr
-rw-rw-r-- 1        0 Mar 18 05:15 testfile
-rw-rw-r-- 1       43 Mar 18 05:03 testout
-rwxrw-r-- 1       30 Mar 18 05:15 test.sh*
-rw-r--r-- 1      102 Mar 17 17:10 test.txt
$ cat test.sh
#!/bin/bash
exec 0< testfile
count=1
while read line
do 
   echo "$count $line"
   count=$[$count+1]
done
$ ./test.sh
1 total 36
2 drwxr-xr-x 2     4096 Mar 18 05:15 ./
3 drwxr-xr-x 4 root root 4096 Mar 14 06:00 ../
4 -rw-r--r-- 1 root root   22 Feb 25 17:37 sed.txt
5 -rw-rw-r-- 1       15 Mar 17 17:23 stderr.txt
6 -rw-rw-r-- 1       47 Mar 17 17:07 stdout.txt
7 -rw-rw-r-- 1       43 Mar 18 05:03 testerr
8 -rw-rw-r-- 1        0 Mar 18 05:15 testfile
9 -rw-rw-r-- 1       43 Mar 18 05:03 testout
10 -rwxrw-r-- 1       30 Mar 18 05:15 test.sh*
11 -rw-r--r-- 1      102 Mar 17 17:10 test.txt

重定向stdin后,read命令不再从stdin中读取输入,而是从testfile中读取输入。
五、创建自己的重定向
1.创建输出文件描述符
在shell中一个进程最多有9个打开的文件描述符,其他6个描述符编号从3-8,在脚本中可以使用这些备选文件描述符。

$ cat test.sh
#!/bin/bash
exec 3> test3file
echo "this is stdout"
echo "this is 3 out" >&3
$ ./test.sh
this is stdout
$ cat test3file 
this is 3 out

脚本使用exec命令将文件描述符3定向到一个文件,当脚本执行echo语句时,重定向到文件描述符3的echo语句输出到了test3file文件中。这样可以实现将普通输出定向到显示屏,将特殊信息重定向到文件(如日志文件)。
2.重定向文件描述符
可以将标准文件描述符重定向到一个备选文件描述符,同样可以将备选文件描述符重定向到一个标准文件描述符。

$ cat test.sh
#!/bin/bash
exec 3>&1
exec 1>stdout
echo "this should store in the output file"
echo "along with this line"

exec 1>&3
echo "Now things should be back to normal"
$ ./test.sh
Now things should be back to normal
$ cat stdout
this should store in the output file
along with this line

在这个例子中,首先(exec 3>&1)脚本将文件描述符3重定向到文件描述符1的当前位置,即屏幕,这样做后,任何发送到描述符3的输出都将会出现在屏幕上,第二个exec(exec 1>stdout)命令将stdout重定向到一个文件stdout,这样做后,任何发送到stdout的输出重定向到文件stdout中,但是文件描述符3仍然指向stdout原来的位置,也就是屏幕,这个时候如果将数据发送到文件描述符3,会显示在屏幕上。第三个exec命令(exec 1>&3)脚本将stdout重定向到文件描述符3的当前位置(屏幕),这样stdout就指向它原来的位置,即屏幕。
3.创建输入文件描述符
使用exec命令可以将stdin文件描述符保存到另一个文件描述符,然后在完成了文件读取操作之后,再将stdin恢复。

$ cat testfile
-rw-rw-r-- 1        0 Mar 18 20:13 testfile
-rw-rw-r-- 1       43 Mar 18 05:03 testout
-rwxrw-r-- 1      177 Mar 18 20:11 test.sh*
-rw-r--r-- 1      102 Mar 17 17:10 test.txt
$ cat test.sh
#!/bin/bash
exec 3<&0
exec 0< testfile
count=1
while read line
do
   echo "$count $line"
   count=$[$count+1]
done 

exec 0<&3
read -p "enter your name: " answer
echo  "$answer"
$ ./test.sh
1 -rw-rw-r-- 1        0 Mar 18 20:13 testfile
2 -rw-rw-r-- 1       43 Mar 18 05:03 testout
3 -rwxrw-r-- 1      177 Mar 18 20:11 test.sh*
4 -rw-r--r-- 1      102 Mar 17 17:10 test.txt
enter your name: jix
jix
$ 

这个脚本中先使用文件描述符6保存stdin的位置(屏幕),然后脚本将stdin重定向到文件testfile,while循环中的read读取的是testfile中内容,最后将stdin重定向到文件描述符6的位置(屏幕),这样stdin又变成了从键盘读取输入。
4.关闭文件描述符
如果创建了新的输入或输出文件描述符,shell将在脚本退出时自动关闭它们,但是有时需要
我们自己手动关闭文件描述符,要关闭文件描述符,要将其重定向到特殊符号”&-“:

exec 3>&- #这条命令会关闭文件描述符3。
$ cat test.sh
#!/bin/bash
exec 3> testfile
echo "this is first  3 out line" >&3
exec 3>&-
echo "this is second 3 out line" >&3
$ ./test.sh
./test.sh: line 5: 3: Bad file descriptor
$ cat testfile
this is first  3 out line

关闭文件描述符后,不能再向其写入数据,否则会报错。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值