shell读书笔记9

19、呈现数据

  1. 理解输入和输出
    至此你已经知道了两种显示脚本输出的方法:
     在显示器屏幕上显示输出
     将输出重定向到文件中
    1.1、标准文件描述符
    Linux用文件描述符(filedescriptor)来标识每个文件对象。文件描述符是一个非负整数,可以唯一标识会话中打开的文件。每个进程一次最多可以有九个文件描述符。出于特殊目的,bash shell保留了前三个文件描述符(0、1和2)
    在这里插入图片描述
    1.2、重定向错误
    有几种办法实现方法:
    I、只重定向错误
    STDERR文件描述符被设成2。可以选择只重定向错误消息,将该文件描述符值放在重定向符号前。该值必须紧紧地放在重定向符号前,否则不会工作

    $ ls -al badfile 2> test4
    $ cat test4
    ls: cannot access badfile: No such file or directory
    $
    

    用这种方法,shell会只重定向错误消息,而非普通数据。这里是另一个将STDOUT和STDERR消息混杂在同一输出中的例子。

    $ ls -al test badtest test2 2> test5
    -rw-rw-r-- 1 rich rich 158 2014-10-16 11:32 test2
    $ cat test5
    ls: cannot access test: No such file or directory
    ls: cannot access badtest: No such file or directory
    $
    

    ls命令的正常STDOUT输出仍然会发送到默认的STDOUT文件描述符,也就是显示器。由于该命令将文件描述符2的输出(STDERR)重定向到了一个输出文件,shell会将生成的所有错误消息直接发送到指定的重定向文件中。

    II、重定向错误和数据
    如果想重定向错误和正常输出,必须用两个重定向符号。需要在符号前面放上待重定向数据所对应的文件描述符,然后指向用于保存数据的输出文件。

    $ ls -al test test2 test3 badtest 2> test6 1> test7
    $ cat test6
    ls: cannot access test: No such file or directory
    ls: cannot access badtest: No such file or directory
    $ cat test7
    -rw-rw-r-- 1 rich rich 158 2014-10-16 11:32 test2
    -rw-rw-r-- 1 rich rich 0 2014-10-16 11:33 test3
    $
    

    shell利用1>符号将ls命令的正常输出重定向到了test7文件,而这些输出本该是进入STDOUT的。所有本该输出到STDERR的错误消息通过2>符号被重定向到了test6文件。

    另外,如果愿意,也可以将STDERR和STDOUT的输出重定向到同一个输出文件。为此bash shell提供了特殊的重定向符号&>。

    $ ls -al test test2 test3 badtest &> test7
    $ cat test7
    ls: cannot access test: No such file or directory
    ls: cannot access badtest: No such file or directory
    -rw-rw-r-- 1 rich rich 158 2014-10-16 11:32 test2
    -rw-rw-r-- 1 rich rich 0 2014-10-16 11:33 test3
    $
    
  2. 在脚本中重定向输出
    有两种方法来在脚本中重定向输出:
     临时重定向行输出
     永久重定向脚本中的所有命令
    I、临时重定向
    如果有意在脚本中生成错误消息,可以将单独的一行输出重定向到STDERR。你所需要做的是使用输出重定向符来将输出信息重定向到STDERR文件描述符。在重定向到文件描述符时,你必须在文件描述符数字之前加一个&:

    echo "This is an error message" >&2
    

    这行会在脚本的STDERR文件描述符所指向的位置显示文本,而不是通常的STDOUT。下面这个例子就利用了这项功能。

    $ cat test8
    #!/bin/bash
    # testing STDERR messages
    echo "This is an error" >&2
    echo "This is normal output"
    $
    如果像平常一样运行这个脚本,你可能看不出什么区别。
    $ ./test8
    This is an error
    This is normal output
    $
    

    记住,默认情况下,Linux会将STDERR导向STDOUT。但是,如果你在运行脚本时重定向了STDERR,脚本中所有导向STDERR的文本都会被重定向。

    $ ./test8 2> test9
    This is normal output
    $ cat test9
    This is an error
    $
    

    太好了!通过STDOUT显示的文本显示在了屏幕上,而发送给STDERR的echo语句的文本则被重定向到了输出文件
    II、永久重定向
    如果脚本中有大量数据需要重定向,那重定向每个echo语句就会很烦琐。取而代之,你可以用exec命令告诉shell在脚本执行期间重定向某个特定文件描述符。

    $ cat test10
    #!/bin/bash
    # redirecting all output to a file
    exec 1>testout
    echo "This is a test of redirecting all output"
    echo "from a script to another file."
    echo "without having to redirect every individual line"
    $ ./test10
    $ cat testout
    This is a test of redirecting all output
    from a script to another file.
    without having to redirect every individual line
    $
    

    exec命令会启动一个新shell并将STDOUT文件描述符重定向到文件。脚本中发给STDOUT的所有输出会被重定向到文件。
    可以在脚本执行过程中重定向STDOUT。

    $ cat test11
    #!/bin/bash
    # redirecting output to different locations
    exec 2>testerror
    echo "This is the start of the script"
    echo "now redirecting all output to another location"
    exec 1>testout
    echo "This output should go to the testout file"
    echo "but this should go to the testerror file" >&2
    $
    $ ./test11
    This is the start of the script
    now redirecting all output to another location
    $ cat testout
    This output should go to the testout file
    $ cat testerror
    but this should go to the testerror file
    $
    

    这个脚本用exec命令来将发给STDERR的输出重定向到文件testerror。接下来,脚本用echo语句向STDOUT显示了几行文本。随后再次使用exec命令来将STDOUT重定向到testout文件。注意,尽管STDOUT被重定向了,但你仍然可以将echo语句的输出发给STDERR,在本例中还是重定向到testerror文件。

  3. 在脚本中重定向输入
    你可以使用与脚本中重定向STDOUT和STDERR相同的方法来将STDIN从键盘重定向到其他位置。exec命令允许你将STDIN重定向到Linux系统上的文件中:

    exec 0< testfile
    

    这个命令会告诉shell它应该从文件testfile中获得输入,而不是STDIN。这个重定向只要在脚本需要输入时就会作用。下面是该用法的实例。

    $ cat test12
    #!/bin/bash
    # redirecting file input
    exec 0< testfile
    count=1
    while read line
    do
    echo "Line #$count: $line"
    count=$[ $count + 1 ]
    done
    $ ./test12
    Line #1: This is the first line.
    Line #2: This is the second line.
    Line #3: This is the third line.
    $
    
  4. 实例
    文件重定向常见于脚本需要读入文件和输出文件时。这个样例脚本两件事都做了。它读取.csv格式的数据文件,输出SQL INSERT语句来将数据插入数据库。shell脚本使用命令行参数指定待读取的.csv文件。.csv格式用于从电子表格中导出数据,所以你可以把数据库数据放入电子表格中,把电子表格保存成.csv格式,读取文件,然后创建INSERT语句将数据插入MySQL数据库。
    脚本内容如下。

    $cat test23
    #!/bin/bash
    # read file and create INSERT statements for MySQL
    outfile='members.sql'
    IFS=','
    while read lname fname address city state zip
    do
    cat >> $outfile << EOF
    INSERT INTO members (lname,fname,address,city,state,zip) VALUES
    ('$lname', '$fname', '$address', '$city', '$state', '$zip');
    EOF
    done < ${1}
    $
    

    这个脚本很短小,这都要感谢有了文件重定向!脚本中出现了三处重定向操作。while循环使用read语句(参见第14章)从数据文件中读取文本。注意在done语句中出现的重定向符号:

    done < ${1}
    

    当运行程序test23时,$1代表第一个命令行参数。它指明了待读取数据的文件。read语句会使用IFS字符解析读入的文本,我们在这里将IFS指定为逗号。
    脚本中另外两处重定向操作出现在同一条语句中:

    cat >> $outfile << EOF
    

    这条语句中包含一个输出追加重定向(双大于号)和一个输入追加重定向(双小于号)。输出重定向将cat命令的输出追加到由$outfile变量指定的文件中。cat命令的输入不再取自标准输入,而是被重定向到脚本中存储的数据。EOF符号标记了追加到文件中的数据的起止。

    INSERT INTO members (lname,fname,address,city,state,zip) VALUES
    ('$lname', '$fname', '$address', '$city', '$state', '$zip');
    

    上面的文本生成了一个标准的SQL INSERT语句。注意,其中的数据会由变量来替换,变量中内容则是由read语句存入的。
    所以基本上while循环一次读取一行数据,将这些值放入INSERT语句模板中,然后将结果输出到输出文件中。
    在这个例子中,使用以下输入数据文件。

    $ cat members.csv
    Blum,Richard,123 Main St.,Chicago,IL,60601
    Blum,Barbara,123 Main St.,Chicago,IL,60601
    Bresnahan,Christine,456 Oak Ave.,Columbus,OH,43201
    Bresnahan,Timothy,456 Oak Ave.,Columbus,OH,43201
    $
    

    运行脚本时,显示器上不会出现任何输出:

    $ ./test23 < members.csv
    $
    

    但是在members.sql输出文件中,你会看到如下输出内容。

    $ cat members.sql
    INSERT INTO members (lname,fname,address,city,state,zip) VALUES ('Blum',
    'Richard', '123 Main St.', 'Chicago', 'IL', '60601');
    INSERT INTO members (lname,fname,address,city,state,zip) VALUES ('Blum',
    'Barbara', '123 Main St.', 'Chicago', 'IL', '60601');
    INSERT INTO members (lname,fname,address,city,state,zip) VALUES ('Bresnahan',
    'Christine', '456 Oak Ave.', 'Columbus', 'OH', '43201');
    INSERT INTO members (lname,fname,address,city,state,zip) VALUES ('Bresnahan',
    'Timothy', '456 Oak Ave.', 'Columbus', 'OH', '43201');
    $
    

    结果和我们预想的一样!现在可以将members.sql文件导入MySQL数据表中了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值