您的位置:首页 > 运维架构 > Shell

linux shell编程指南第五章------shell输入与输出1

2013-11-21 23:25 330 查看
在使用c a t命令时要注意,它不会在文件分页符处停下来;它会一下显示完整个文

件。如果希望每次显示一页,可以使用m o r e命令或把c a t命令的输出通过管道传递到另外一个

具有分页功能的命令中,

$ cat myfile | more



$ cat myfile | pg

如果希望创建一个名为b i g f i l e的文件,该文件包含上述三个文件的内容,可以把上面命令

的输出重定向到新文件中:

$ cat myfile1 myfile2 myfile3 > bigfile

如果希望创建一个新文件,并向其中输入一些内容,只需使用c a t命令把标准输出重定向

到该文件中,这时c a t命令的输入是标准输入—键盘,你输入一些文字,输入完毕后按

< C T R L - D >结束输入。这真是一个非常简单的文字编辑器!

[root@localhost huangcd]# cat > myfile1.txt

nihao

huangchengdu

[root@localhost huangcd]# cat myfile1.txt

nihao

huangchengdu

还可以使用c a t命令来显示控制字符。这里有一个对从D O S机器上f t p过来的文件进行检察

的例子,在这个例子中,所有的控制字符< C T R L - M >都在行末显示了出来。

[root@localhost huangcd]# cat -v dos.txt

12332##DISO##45.12

00332##LPSO##23.11

01299##USPD##34.46

可以通过管道把一个命令的输出传递给另一个命令作为输入。管道用竖杠|表示。它的一

般形式为:

命令1 |命令2

其中|是管道符号。

在下面的例子中,在当前目录中执行文件列表操作,如果没有管道的话,所有文件就会

显示出来。当s h e l l看到管道符号以后,就会把所有列出的文件交给管道右边的命令,因此管

道的含义正如它的名字所暗示的那样:把信息从一端传送到另外一端。

可以通过管道把一个命令的输出传递给另一个命令作为输入。管道用竖杠|表示

s e d、a w k和g r e p都很适合用管道,特别是在简单的一行命令中。在下面的例子中, w h o命

令的输出通过管道传递给a w k命令,以便只显示用户名和所在的终端。

[root@localhost huangcd]# who | awk '{print $1"\t"$2}'

root :0

root pts/1

如果你希望列出系统中所有的文件系统,可以使用管道把d f命令的输出传递给a w k命令,

a w k显示出其中的第一列。你还可以再次使用管道把a w k的结果传递给g r e p命令,去掉最上面

的题头f i l e s y s t e m。

[root@localhost huangcd]# df -k |awk '{print $1}'|grep -v "Filesystem"

文件系统

/dev/sda2

/dev/sda3

/dev/sda1

tmpfs

[root@localhost huangcd]# df -k |awk '{print $1}'|grep -v "文件系统"

/dev/sda2

/dev/sda3

/dev/sda1

tmpfs

当然,你没准还会希望只显示出其中的分区名,不显示/ d e v /部分,这没问题;我们只要

在后面简单地加上另一个管道符号和相应的s e d命令即可。

[root@localhost huangcd]# df -k |awk '{print $1}'|grep -v "Filesystem"|sed s'/\/dev\///g'

文件系统

sda2

sda3

sda1

tmpfs

t e e命令作用可以用字母T来形象地表示。它把输出的一个副本输送到标准输出,另一个

副本拷贝到相应的文件中。如果希望在看到输出的同时,也将其存入一个文件,那么这个命

令再合适不过了。

它的一般形式为:

tee -a files

其中,- a表示追加到文件末尾。

当执行某些命令或脚本时,如果希望把输出保存下来, t e e命令非常方便。

下面我们来看一个例子,我们使用w h o命令,结果输出到屏幕上,同时保存在w h o . o u t文

[root@localhost huangcd]# who|tee who.out

root :0 2013-11-21 19:28

root pts/1 2013-11-21 21:42 (:0.0)

[root@localhost huangcd]# cat who.out

root :0 2013-11-21 19:28

root pts/1 2013-11-21 21:42 (:0.0)

[root@localhost huangcd]# echo "huangchengdu nihao"|tee -a myscript.log

huangchengdu nihao

[root@localhost huangcd]# cat myscript.log

huangchengdu nihao

当我们在s h e l l中执行命令的时候,每个进程都和三个打开的文件相联系,并使用文件描

述符来引用这些文件。由于文件描述符不容易记忆, s h e l l同时也给出了相应的文件名。

输入文件—标准输入 0

输出文件—标准输出 1

错误输出文件—标准错误 2

系统中实际上有1 2个文件描述符,但是正如我们在上表中所看到的, 0、1、2是标准输入、

输出和错误。可以任意使用文件描述符3到9。

标准输入是文件描述符0。它是命令的输入,缺省是键盘,也可以是文件或其他命令的输出。

标准输出是文件描述符1。它是命令的输出,缺省是屏幕,也可以是文件。

标准错误是文件描述符2。这是命令错误的输出,缺省是屏幕,同样也可以是文件。你可

能会问,为什么会有一个专门针对错误的特殊文件?这是由于很多人喜欢把错误单独保存到

一个文件中,特别是在处理大的数据文件时,可能会产生很多错误。

在对标准错误进行重定向时,必须要使用文件描述符,但是对于标准输入和输出来说,

这不是必需的。为了完整起见,我们在表5 - 1中列出了两种方法。



让我们来看一个标准输出的例子。在下面的命令中,把/ e t c / p a s s w d文件中的用户I D域按

照用户命排列。该命令的输出重定向到s o r t . o u t文件中。要提醒注意的是,在使用s o r t命令的时

候(或其他含有相似输入文件参数的命令),重定向符号一定要离开s o r t命令两个空格,否则该

命令会把它当作输入文件。

[root@localhost huangcd]# cat /etc/passwd |awk -F: '{print $1}'|sort 1>sort.out

[root@localhost huangcd]# cat sort.out

adm

apache

avahi

avahi-autoipd

bin

daemon

dbus

distcache

dovecot

ftp

可以把很多命令的输出追加到同一文件中。

如果希望把标准输出重定向到文件中,可以用> f i l e n a m e。在下面的例子中, l s命令的所

有输出都被重定向到l s . o u t文件中:

$ ls >ls.out

如果希望追加到已有的文件中(在该文件不存在的情况下创建该文件),那么可以使用

[root@localhost huangcd]# cat myscript.log

huangchengdu nihao

[root@localhost huangcd]# pwd >>myscript.log

[root@localhost huangcd]# cat myscript.log

huangchengdu nihao

/home/huangcd

重定向标准输入:

可以指定命令的标准输入。在a w k一章就会遇到这样的情况。下面给出一个这样的例子:

$ sort < name.txt

在上面的命令中, s o r t命令的输入是采用重定向的方式给出的,不过也可以直接把相应的

文件作为该命令的参数:

$ sort name.txt

在上面的例子中,还可以更进一步地通过重定向为s o r t命令指定一个输出文件n a m e . o u t。

这样屏幕上将不会出现任何信息(除了错误信息以外):

$ sort <name.txt >name.out

在发送邮件时,可以用重定向的方法发送一个文件中的内容。在下面的例子中,用户

l o u i s e将收到一个邮件,其中含有文件c o n t e n t s . t x t中的内容:

$ mail louise < contents.txt

重定向操作符command << delimiter是一种非常有用的命令,通常都被称为“此处”文挡。

我们将在本书后面的章节深入讨论这一问题。现在只介绍它的功能。s h e l l将分界符d e l i m i t e r之

后直至下一个同样的分界符之前的所有内容都作为输入,遇到下一个分界符, s h e l l就知道输

入结束了。这一命令对于自动或远程的例程非常有用。可以任意定义分界符d e l i m i t e r,最常见

的是E O F,而我最喜欢用M AY D AY,这完全取决于个人的喜好。还可以在< <后面输入变量。

下面给出一个例子,我们创建了一个名为m y f i l e的文件,并在其中使用了T E R M和L O G N A M E

变量。

[root@localhost etc]# cat >>myfile <<MAYDAY

> hello huangchengdu

> did you had ate deer

> hahahaha

> MAYDAY

[root@localhost etc]# cat myfile

hello huangchengdu

did you had ate deer

hahahaha

重定向标准错误:

为了重定向标准错误,可以指定文件描述符2。让我们先来看一个例子,因为举例子往往

会让人更容易明白。在这个例子中, g r e p命令在文件m i s s i l e s中搜索t r i d e n t字符串:

[root@localhost huangcd]# grep "trident" missiles

grep: missiles: 没有那个文件或目录

g r e p命令没有找到该文件,缺省地向终端输出了一个错误信息。现在让我们把错误重定

向到文件/ d e v / n u l l中(实际就上是系统的垃圾箱):

$ grep "trident" missiles 2>/dev/null

这样所有的错误输出都输送到了/ d e v / n u l l,不再出现在屏幕上。

如果你在对更重要的文件进行操作,可能会希望保存相应的错误。下面就是一个这样的

例子,这一次错误被保存到g r e p . e r r文件中:

[root@localhost huangcd]# grep "trdient" missiles 2>grep.err

[root@localhost huangcd]# cat grep.err

grep: missiles: 没有那个文件或目录

还可以把错误追加到一个文件中。在使用一组命令完成同一个任务时,这种方法非常有

用。在下面的例子中,两个g r e p命令把错误都输出到同一个文件中;由于我们使用了> >符号

进行追加,后面一个命令的错误(如果有的话)不会覆盖前一个命令的错误。

[root@localhost huangcd]# grep "LPSO" missiles 2>>grep.err

[root@localhost huangcd]# cat grep.err

grep: missiles: 没有那个文件或目录

grep: missiles: 没有那个文件或目录

结合使用标准输出和标准错误:

一个快速发现错误的方法就是,先将输出重定向到一个文件中,然后再把标准错误重定

向到另外一个文件中。下面给出一个例子:

我有两个审计文件,其中一个的确存在,而且包含一些信息,而另一个由于某种原因已

经不存在了(但我不知道)。我想把这两个文件合并到a c c o u n t s . o u t文件中。

$ cat account_qtr.doc account_end.doc 1>accounts.out 2>accounts.err

现在如果出现了错误,相应的错误将会保存在a c c o u n t s . e r r文件中。

合并标准输出和标准错误:

在合并标准输出和标准错误的时候,切记s h e l l是从左至右分析相应的命令的。下面给出

一个例子:

$ cleanup >cleanup.out 2>&1

在上面的例子中,我们将c l e a n u p脚本的输出重定向到c l e a n u p . o u t文件中,而且其错误也

被重定向到相同的文件中。

$ grep "standard"* > grep.out 2>&1

在上面的例子中, g r e p命令的标准输出和标准错误都被重定向到g r e p . o u t文件中。你在使

用前面提到的“此处”文挡时,有可能需要把所有的输出都保存到一个文件中,这样万一出

现了错误,就能够被记录下来。通过使用2 > & 1就可以做到这一点,下面给出一个例子:

[root@localhost huangcd]# cat>>filetest 2>&1 <<MAYDAY

> this is my home $HOME directory

> hello huang chengdu

> MAYDAY

[root@localhost huangcd]# cat filetest

nihao huangchengdu

my home is /root

HAHAHHAHA

this is my home /root directory

hello huang chengdu

[root@localhost huangcd]# cat>>filetest 2>&1 <<EOF

> nihao huangchengdu

> my home is $HOME

> HAHAHHAHA

> EOF

[root@localhost huangcd]# cat filetest

nihao huangchengdu

my home is /root

HAHAHHAHA

exec:

e x e c命令可以用来替代当前s h e l l;换句话说,并没有启动子s h e l l。使用这一命令时任何现

有环境都将会被清除,并重新启动一个s h e l l。它的一般形式为:

exec command

其中的c o m m a n d通常是一个s h e l l脚本。

我所能够想像得出的描述e x e c命令最贴切的说法就是:它践踏了你当前的s h e l l。

当这个脚本结束时,相应的会话可能就结束了。e x e c命令的一个常见用法就是在用户

的. p r o f i l e最后执行时,用它来执行一些用于增强安全性的脚本。如果用户的输入无效,该

s h e l l将被关闭,然后重新回到登录提示符。e x e c还常常被用来通过文件描述符打开文件。

记住, e x e c在对文件描述符进行操作的时候(也只有在这时),它不会覆盖你当前的

s h e l l。

使用文件描述符:

可以使用e x e c命令通过文件描述符打开和关闭文件。在下面的例子中,我选用了文件描

述符4,实际上我可以在4到9之间任意选择一个数字。下面的脚本只是从s t o c k . t x t文件中读了

两行,然后把这两行回显出来。

该脚本的第一行把文件描述符4指定为标准输入,然后打开s t o c k . t x t文件。接下来两行的

作用是读入了两行文本。接着,作为标准输入的文件描述符4被关闭。最后,l i n e 1和l i n e 2两个

变量所含有的内容被回显到屏幕上。

[root@localhost huangcd]# cat stock.txt

Crayons Assorted 34

Pencils Light 12

[root@localhost huangcd]# cat f_desc

#!/bin/bash

exec 4<&0 0<stock.txt

read line1

read line2

exec 0<&4

echo $line1

echo $line2

[root@localhost huangcd]# sh f_desc

Crayons Assorted 34

Pencils Light 12
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: