shell的输入与输出
在shell脚步中,可以用几种不同的方式读取数据:可以使用标准输入--缺省为键盘,或者指定一个文件作为输入。
同样,对于输出,如果不指定某个文件作为输出,标准输出总是和终端屏幕相关联。
--echo
使用echo命令可以显示文本行或者变量,或者把字符串输入到文件。
它的一般形式为:
echo string
echo命令有很多功能,其中最常用的有:
\c 不换行
\t 跳格
\n 换行
linux中使用“-n”选项来禁止echo命令输出后换行:
# echo -n "what name: "
必须使用-e选项才能使转义符生效:
echo -e "what name: \t luyx \n"
如果想把一个字符串输出到文件中,使用重定向符合> :
echo "The log files have all been done">myfile
如何把双引号包含到e c h o命令的字符串中。引号是一个特殊字符,所以必须要使用反斜杠\来使s h e l l忽略它的特殊含义。假设你希望使用echo命令输出这样的字符串:“/dev/rmt0”,那么我们只要在引号前面加上反斜杠\即可:
echo "\"/dev/rmt0"\" 结果显示为:"/dev/rmt0"
--read
可以使用read语句从键盘或文件的某一行文本中读入信息,并将其赋值给一个变量。
如果只指定一个变量,那么read将会把所有的输入赋给该变量,直到遇到第一个文件结束符或者回车。
read的一般形式:
read varible1 varible2 .....
下面的例子中,只指定一个变量,它将被赋予直至回车之前的所有内容
[root@localhost ~]# read name
Hello I am superman
[root@localhost ~]# echo $name
Hello I am superman
下面的例子中,我们给出了两个变量,它们分别被赋予名字和姓氏。s h e l l将用空格作为变量之间的分隔符:
[root@localhost ~]# read name surname
yongxin lu
[root@localhost ~]# echo $name $surname
yongxin lu
如果输入文本域过长, Shell 将所有的超长部分赋予最后一个变量。下面的例子,假定要读取变量名字和姓,但这次输入三个名字;
[root@localhost ~]# read name surname
John Lemon doe
[root@localhost ~]# echo $name
John
[root@localhost ~]# echo $surname
Lemon doe
在上面的例子中,如果我们输入字符串John Lemon Doe,那么第一个单词将被赋给第一个变量,而由于变量数少于单词数,字符串后面的部分将被全部赋给第二个变量
在编写s h e l l脚本的时候,如果担心用户会对此感到迷惑,可以采用每一个r e a d语句只给一
个变量赋值的办法:
[root@localhost ~]# vi test.sh
#
echo -e "fisrt name:\c"
read name
echo -e "Middle name:\c"
read middle
echo -e "last name:\c"
read surname
--cat
c a t是一个简单而通用的命令,可以用它来显示文件内容,创建文件,还可以用它来显示
控制字符。在使用c a t命令时要注意,它不会在文件分页符处停下来;它会一下显示完整个文
件。如果希望每次显示一页,可以使用m o r e命令或把c a t命令的输出通过管道传递到另外一个
具有分页功能的命令中,请看下面的例子:
$cat myfiel | more
cat命令的一般形式为:
cat [options] filename1 ... filename2 ...
cat命令最有用的选项就是:
-v 显示控制字符
如果希望显示名为myfile的文件,可以用:
$ cat myfile
如果希望显示myfile1、myfile2、myfile3这三个文件,可以用:
$ cat myfile1 myfile2 myfile3
如果希望创建一个名为big file的文件,该文件包含上述三个文件的内容,可以把上面命令
的输出重定向到新文件中:
$ cat myfile1 myfile2 myfile3 > bigfile
如果希望创建一个新文件,并向其中输入一些内容,只需使用c a t命令把标准输出重定向到该文件中,这时c a t命令的输入是标准输入—键盘,你输入一些文字,输入完毕后按< C T R L - D >结束输入。这真是一个非常简单的文字编辑器!
[root@localhost ~]# cat > myfile
Hello world
< C T R L - D >
有一点要提醒的是,如果在敲入了c a t以后就直接按回车,该命令会等你输入字符。如果你本来就是要输入一些字符,那么它除了会在你输入时在屏幕上显示以外,还会再回显这些内容;最后按< C T R L - D >结束输入即可。
[root@localhost ~]# cat
my name
my name
luyx
luyx
--管道
可以通过管道把一个命令的输出传递给另一个命令作为输入。管道用竖杠|表示。它的一
般形式为:
命令1 |命令2
其中|是管道符号。
在下面的例子中,在当前目录中执行文件列表操作,如果没有管道的话,所有文件就会显示出来。当s h e l l看到管道符号以后,就会把所有列出的文件交给管道右边的命令,因此管道的含义正如它的名字所暗示的那样:把信息从一端传送到另外一端。在这个例子中,接下来g r e p命令在文件列表中搜索myfile:
[root@localhost ~]# ls |grep myfile
myfile
s e d、a w k和g r e p都很适合用管道,特别是在简单的一行命令中。在下面的例子中, w h o命
令的输出通过管道传递给a w k命令,以便只显示用户名和所在的终端。
[root@localhost ~]# who
root tty1 Mar 14 15:35
root pts/0 Mar 15 07:10 (192.168.50.1)
root pts/2 Mar 15 08:33 (192.168.50.1)
[root@localhost ~]# who | awk '{print $1 "\t"$2}'
root tty1
root pts/0
root pts/2
--tee
t e e命令作用可以用字母T来形象地表示。它把输出的一个副本输送到标准输出,另一个副本拷贝到相应的文件中。如果希望在看到输出的同时,也将其存入一个文件,那么这个命令再合适不过了。
它的一般形式为:
tee -a files
其中,- a表示追加到文件末尾。
[root@localhost ~]# who |tee who.out
root tty1 Mar 14 15:35
root pts/0 Mar 15 07:10 (192.168.50.1)
root pts/2 Mar 15 08:33 (192.168.50.1)
[root@localhost ~]# cat who.out
root tty1 Mar 14 15:35
root pts/0 Mar 15 07:10 (192.168.50.1)
root pts/2 Mar 15 08:33 (192.168.50.1)
标准输入、输出和错误
当我们在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列出了最常用的重定向组合,并给出了相应的文件描述符。在对标准错误进行重定向时,必须要使用文件描述符,但是对于标准输入和输出来说,这不是必需的。为了完整起见,我们在表5 - 1中列出了两种方法。
表5-1 常用文件重定向命令
command > filename 把把标准输出重定向到一个新文件中
command >> filename 把把标准输出重定向到一个文件中(追加)
command 1 > fielname 把把标准输出重定向到一个文件中
command > filename 2>&1 把把标准输出和标准错误一起重定向到一个文件中
command 2 > filename 把把标准错误重定向到一个文件中
command 2 >> filename 把把标准输出重定向到一个文件中(追加)
command >> filename 2>&1 把把标准输出和标准错误一起重定向到一个文件中(追加)
command < filename >filename2 把command命令以filename文件作为标准输入,以filename2文作为标准输出
command < filename 把c o m m a n d命令以f i l e n a m e文件作为标准输入
command << delimiter 把从标准输入中读入,直至遇到d e l i m i t e r分界符
command <&m 把把文件描述符m作为标准输入
command >&m 把把标准输出重定向到文件描述符m中
command <&- 把关闭标准输入
重定向标准输出
让我们来看一个标准输出的例子。在下面的命令中,把/etc/passwd文件中的用户I D域按照用户命排列。该命令的输出重定向到sort.out文件中。要提醒注意的是,在使用sort命令的时候(或其他含有相似输入文件参数的命令),重定向符号一定要离开sort命令两个空格,否则该命令会把它当作输入文件。
$ cat passwd | awk -F: '{print $1}' | sort 1>sort.out
从表5 - 1中可以看出,我们也可以使用如下的表达方式,结果和上面一样:
$ cat passwd | awk -F: '{print $1}' | sort >sort.out
如果希望追加到已有的文件中(在该文件不存在的情况下创建该文件),那么可以使用> > f i l e n a m e:
[root@localhost ~]# pwd >>pwd.out
重定向标准输入
可以指定命令的标准输入。在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是一种非常有用的命令,通常都被称为“此处”文挡。
现在只介绍它的功能。shell将分界符delimiter之后直至下一个同样的分界符之前的所有内容都作为输入,遇到下一个
可以任意定义分界符delimiter,最常见的是EoF
[root@localhost ~]# cat >>myfile <<EOF
> hell there i am using a $TERM termina
> EOF
[root@localhost ~]# cat myfile
there i am using a vt100 termina
重定向标准错误
为了重定向标准错误,可以指定文件描述符2。让我们先来看一个例子,因为举例子往往会让人更容易明白。在这个例子中, g r e p命令在文件m i s s i l e s中搜索t r i d e n t字符串:
[root@localhost ~]# grep "luyx" missiles
grep: missiles: No such file or directory
g r e p命令没有找到该文件,缺省地向终端输出了一个错误信息。现在让我们把错误重定向到文件 /dev/null 中(实际就上是系统的垃圾箱):
[root@localhost ~]# grep "luyx" missiles 2>/dev/null
[root@localhost ~]#
这样所有的错误输出都输送到了/ d e v / n u l l,不再出现在屏幕上。
如果你在对更重要的文件进行操作,可能会希望保存相应的错误。下面就是一个这样的
例子,这一次错误被保存到g r e p . e r r文件中:
[root@localhost ~]# grep "luyx" missiles 2>grep.err
[root@localhost ~]# cat grep.err
grep: missiles: No such file or directory
还可以把错误追加到一个文件中。在使用一组命令完成同一个任务时,这种方法非常有用。在下面的例子中,两个g r e p命令把错误都输出到同一个文件中;由于我们使用了> >符号进行追加,后面一个命令的错误(如果有的话)不会覆盖前一个命令的错误。
[root@localhost ~]# grep "luyx" missiles 2>grep.err
[root@localhost ~]# grep "root" missiles 2>grep.err
结合使用标准输出和标准错误
一个快速发现错误的方法就是,先将输出重定向到一个文件中,然后再把标准错误重定向到另外一个文件中。下面给出一个例子:我有两个审计文件,其中一个的确存在,而且包含一些信息,而另一个由于某种原因已经不存在了(但我不知道)。我想把这两个文件合并到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文件中。
================
有关tee/重定向/标准错误输出这些使用,在《shell 重定向的深入》 中涉及到了。
我当初在学重定向深入的时候,早把这篇中的有关知识给忘记了,再次说明复习总结的重要性。不过很长时间不用确实也难免有忘记的部分
有关read命令,在逐行读取文件时有使用到。
=====再做补充===========
1. 标准输入与输出
我们知道,执行一个shell命令行时通常会自动打开三个标准文件,即标准输入文件(stdin),通常对应终端的键盘;标准输出文件(stdout)和标准错误输出文件(stderr),这两个文件都对应终端的屏幕。进程将从标准输入文件中得到输入数据,将正常输出数据输出到标准输出文件,而将错误信息送到标准错误文件中。
我们以cat命令为例,cat命令的功能是从命令行给出的文件中读取数据,并将这些数据直接送到标准输出。若使用如下命令:
$ cat config
将会把文件config的内容依次显示到屏幕上。但是,如果cat的命令行中没有参数,它就会从标准输入中读取数据,并将其送到标准输出。例如:
$ cat
Hello world
Hello world
Bye
Bye
$
用户输入的每一行都立刻被cat命令输出到屏幕上。
另一个例子,命令sort按行读入文件正文(当命令行中没有给出文件名时,表示从标准输入读入),将其排序,并将结果送到标准输出。下面的例子是从标准输入读入一个采购单,并将其排序。
$ sort
bananas
carrots
apples
apples
bananas
carrots
$
这时我们在屏幕上得到了已排序的采购单。直接使用标准输入/输出文件存在以下问题:
输入数据从终端输入时,用户费了半天劲输入的数据只能用一次。下次再想用这些数据时就得重新输入。而且在终端上输入时,若输入有误修改起来不是很方便。
输出到终端屏幕上的信息只能看不能动。我们无法对此输出作更多处理,如将输出作为另一命令的输入进行进一步的处理等。
为了解决上述问题,Linux系统为输入、输出的传送引入了另外两种机制,即输入/输出重定向和管道。
输入重定向
输入重定向是指把命令(或可执行程序)的标准输入重定向到指定的文件中。也就是说,输入可以不来自键盘,而来自一个指定的文件。所以说,输入重定向主要用于改变一个命令的输入源,特别是改变那些需要大量输入的输入源。
例如,命令wc统计指定文件包含的行数、单词数和字符数。如果仅在命令行上键入:
$ wc
wc将等待用户告诉它统计什么,这时shell就好象死了一样,从键盘键入的所有文本都出现在屏幕上,但并没有什么结果,直至按下<ctrl+d>,wc才将命令结果写在屏幕上。
如果给出一个文件名作为wc命令的参数,如下例所示,wc将返回该文件所包含的行数、单词数和字符数。
$ wc /etc/passwd
20 23 726 /etc/passwd
$
另一种把/etc/passwd文件内容传给wc命令的方法是重定向wc的输入。输入重定向的一般形式为:命令<文件名。可以用下面的命令把wc命令的输入重定向为/etc/passwd文件:
$ wc < /etc/passwd
20 23 726
$
另一种输入重定向称为here文档,它告诉shell当前命令的标准输入来自命令行。here文档的重定向操作符使用<<。它将一对分隔符(本例中用delim表示)之间的正文重定向输入给命令。下例将一对分隔符delim之间的正文作为wc命令的输入,统计出正文的行数、单词数和字符数。
$ wc<
>this text forms the content
>of the here document,which
>continues until the end of
>text delimter
>delim
4 17 98
在<<操作符后面,任何字符都可以作为正文开始前的分隔符,本例中使用delim作为分隔符。here文档的正文一直延续到遇见另一个分隔符为止。第二个分隔符应出现在新行的开头。这时here文档的正文(不包括开始和结束的分隔符)将重新定向送给命令wc作为它的标准输入。
由于大多数命令都以参数的形式在命令行上指定输入文件的文件名,所以输入重定向并不经常使用。尽管如此,当要使用一个不接受文件名作为输入参数的命令,而需要的输入内容又存在一个文件里时,就能用输入重定向解决问题。输出重定向
输出重定向
是指把命令(或可执行程序)的标准输出或标准错误输出重新定向到指定文件中。这样,该命令的输出就不显示在屏幕上,而是写入到指定文件中。
输出重定向比输入重定向更常用,很多情况下都可以使用这种功能。例如,如果某个命令的输出很多,在屏幕上不能完全显示,那么将输出重定向到一个文件中,然后再用文本编辑器打开这个文件,就可以查看输出信息;如果想保存一个命令的输出,也可以使用这种方法。还有,输出重定向可以用于把一个命令的输出当作另一个命令的输入(还有一种更简单的方法,就是使用管道,将在下面介绍)。
输出重定向的一般形式为:命令>文件名。例如:
$ ls > directory.out
$ cat directory.out
ch1.doc ch2.doc ch3.doc chimp config mail/ test/
$
将ls命令的输出保存为一个名为directory.out的文件。
注:如果>符号后边的文件已存在,那么这个文件将被重写。
为避免输出重定向中指定文件只能存放当前命令的输出重定向的内容,shell提供了输出重定向的一种追加手段。输出追加重定向与输出重定向的功能非常相似,区别仅在于输出追加重定向的功能是把命令(或可执行程序)的输出结果追加到指定文件的最后,而该文件原有内容不被破坏。
如果要将一条命令的输出结果追加到指定文件的后面,可以使用追加重定向操作符>>。形式为:命令>>文件名。例如:
$ ls *.doc>>directory.out
$ cat directory.out
ch1.doc ch2.doc ch3.doc chimp config mail/ test/
ch1.doc ch2.doc ch3.doc
$
和程序的标准输出重定向一样,程序的错误输出也可以重新定向。使用符号2>(或追加符号2>>)表示对错误输出设备重定向。例如下面的命令:
$ ls /usr/tmp 2> err.file
可在屏幕上看到程序的正常输出结果,但又将程序的任何错误信息送到文件err.file中,以备将来检查用。
还可以使用另一个输出重定向操作符(&>)将标准输出和错误输出同时送到同一文件中。例如:
$ ls /usr/tmp &> output.file
利用重定向将命令组合在一起,可实现系统单个命令不能提供的新功能。例如使用下面的命令序列:
$ ls /usr/bin > /tmp/dir
$ wc –w < /tmp/dir
459
统计了/usr/bin目录下的文件个数。
管 道
将一个程序或命令的输出作为另一个程序或命令的输入,有两种方法,一种是通过一个临时文件将两个命令或程序结合在一起,例如上个例子中的/tmp/dir文件将ls和wc命令联在一起;另一种是Linux所提供的管道功能。这种方法比前一种方法更好。
管道可以把一系列命令连接起来,这意味着第一个命令的输出会作为第二个命令的输入通过管道传给第二个命令,第二个命令的输出又会作为第三个命令的输入,以此类推。显示在屏幕上的是管道行中最后一个命令的输出(如果命令行中未使用输出重定向)。
通过使用管道符“|”来建立一个管道行。用管道重写上面的例子:
$ ls /usr/bin|wc -w
1789
再如:
$ cat sample.txt|grep "High"|wc -l
管道将cat命令(列出一个文件的内容)的输出送给grep命令。grep命令在输入里查找单词High,grep命令的输出则是所有包含单词High的行,这个输出又被送给wc命令,wc命令统计出输入中的行数。假设sample.txt文件的内容如下:
Things to do today:
Low:Go grocery shopping
High:Return movie
High:Clear level 3 in Alien vs. Predator
Medium:Pick up clothes from dry cleaner
那么该管道行的结果是2。
命令替换
命令替换和重定向有些相似,但区别在于命令替换是将一个命令的输出作为另外一个命令的参数。常用命令格式为:
command1 `command2`
其中,command2的输出将作为command1的参数。需要注意的是这里的`符号,被它括起来的内容将作为命令执行,执行后的结果作为command1的参数。例如:
$ cd `pwd`
该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下。