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

来源:互联网 发布:查看端口占用 编辑:程序博客网 时间:2024/06/05 20:11

使用重定向我们可以将程序输入和输出定向到指定的位置,而不仅仅只是显示在屏幕上。在学习重定向之前,先要学习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 hellohelloworldworld^C

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

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

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

$ cat test.txt i have an applei 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.txtFri 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/bashecho "this is stderr" >&2echo "this is stdout."$ ./test.shthis is stderrthis is stdout.$ ./test.sh 2> stderr.txt this is stdout.$ cat stderr.txt this is stderr

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

$ cat test.sh#!/bin/bashexec 1> testoutexec 2> testerrecho "this is first stdout" echo "this is second stdout"echo "this is first stderr" >&2echo "this is second stderr" >&2$ ./test.sh$ cat testout this is first stdoutthis is second stdout$ cat testerr this is first stderrthis is second stderr

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

exec 0> testfile

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

$ cat testfiletotal 36drwxr-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/bashexec 0< testfilecount=1while read linedo    echo "$count $line"   count=$[$count+1]done$ ./test.sh1 total 362 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.txt5 -rw-rw-r-- 1       15 Mar 17 17:23 stderr.txt6 -rw-rw-r-- 1       47 Mar 17 17:07 stdout.txt7 -rw-rw-r-- 1       43 Mar 18 05:03 testerr8 -rw-rw-r-- 1        0 Mar 18 05:15 testfile9 -rw-rw-r-- 1       43 Mar 18 05:03 testout10 -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/bashexec 3> test3fileecho "this is stdout"echo "this is 3 out" >&3$ ./test.shthis is stdout$ cat test3file this is 3 out

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

$ cat test.sh#!/bin/bashexec 3>&1exec 1>stdoutecho "this should store in the output file"echo "along with this line"exec 1>&3echo "Now things should be back to normal"$ ./test.shNow things should be back to normal$ cat stdoutthis should store in the output filealong 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/bashexec 3<&0exec 0< testfilecount=1while read linedo   echo "$count $line"   count=$[$count+1]done exec 0<&3read -p "enter your name: " answerecho  "$answer"$ ./test.sh1 -rw-rw-r-- 1        0 Mar 18 20:13 testfile2 -rw-rw-r-- 1       43 Mar 18 05:03 testout3 -rwxrw-r-- 1      177 Mar 18 20:11 test.sh*4 -rw-r--r-- 1      102 Mar 17 17:10 test.txtenter your name: jixjix$ 

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

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

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

1 0