继: Linux shell 脚本编程-实战篇(一)

2. 创建与数据库、Web及电子邮件相关的脚本


2.1 MySQL 数据库


2.1.1 MySQL 数据库安装


到 http://repo.mysql.com/ 找到合适的 MySQL 版本的 YUM 库 rpm 安装包,复制下载地址,然后执行下面指令安装 YUM 库:

[devalone@devalone mysql]$ sudo dnf install -y http://repo.mysql.com/mysql57-community-release-fc24.rpm

检验 YUM 库已成功安装:

[devalone@devalone mysql]$ cat /etc/yum.repos.d/mysql-community.repo
    [mysql-connectors-community]
    name=MySQL Connectors Community
    baseurl=http://repo.mysql.com/yum/mysql-connectors-community/fc/$releasever/$basearch/
    enabled=1
    gpgcheck=1
    gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql

[mysql-tools-community]
    name=MySQL Tools Community
    baseurl=http://repo.mysql.com/yum/mysql-tools-community/fc/$releasever/$basearch/
    enabled=1
    gpgcheck=1
    gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql

# Enable to use MySQL 5.6
    [mysql56-community]
    name=MySQL 5.6 Community Server
    enabled=0
    baseurl=http://repo.mysql.com/yum/mysql-5.6-community/fc/$releasever/$basearch/
    gpgcheck=1
    gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql

[mysql57-community]
    name=MySQL 5.7 Community Server
    enabled=1
    baseurl=http://repo.mysql.com/yum/mysql-5.7-community/fc/$releasever/$basearch/
    gpgcheck=1
    gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql

[mysql80-community]
    name=MySQL 8.0 Community Server
    baseurl=http://repo.mysql.com/yum/mysql-8.0-community/fc/$releasever/$basearch/
    enabled=0
    gpgcheck=1
    gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql

[mysql-tools-preview]
    name=MySQL Tools Preview
    baseurl=http://repo.mysql.com/yum/mysql-tools-preview/fc/$releasever/$basearch/
    enabled=0
    gpgcheck=1
    gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql

确认:
     [mysql57-community]
    name=MySQL 5.7 Community Server
    enabled=1

其它项目: enabled=0

执行以下指令安装 MySQL 服务器:

[devalone@devalone mysql]$ sudo dnf install mysql-community-server
    
    上次元数据过期检查:0:16:05 前,执行于 Mon Jul 16 11:33:57 2018。
    依赖关系解决。
    ==================================================================================================================================
     Package                            架构               版本                                   仓库                           大小
    ==================================================================================================================================
    安装:
     mecab                              x86_64             0.996-1.fc24.4                         fedora                        386 k
     mecab-ipadic                       x86_64             2.7.0.20070801-12.fc24.1               fedora                         11 M
     mysql-community-client             x86_64             5.7.19-1.fc24                          mysql57-community              25 M
     mysql-community-common             x86_64             5.7.19-1.fc24                          mysql57-community             277 k
     mysql-community-libs               x86_64             5.7.19-1.fc24                          mysql57-community             2.2 M
     mysql-community-server             x86_64             5.7.19-1.fc24                          mysql57-community             135 M

事务概要
    ==================================================================================================================================
    安装  6 软件包

总下载:174 M
    安装大小:788 M
    确定吗?[y/N]: y

输入 y 回车开始安装服务器...

安装完之后启动 mysqld 并配置自启动服务:

[devalone@devalone mysql]$ sudo systemctl start mysqld.service
    [devalone@devalone mysql]$ sudo systemctl enable mysqld.service
    [devalone@devalone mysql]$ sudo systemctl status mysqld.service
    ● mysqld.service - MySQL Server
       Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
       Active: active (running) since 一 2018-07-16 12:11:27 CST; 4s ago
         Docs: man:mysqld(8)
               http://dev.mysql.com/doc/refman/en/using-systemd.html
      Process: 3544 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid $MYSQLD_OPTS (code=exited, status=0/S
      Process: 3465 ExecStartPre=/usr/bin/mysqld_pre_systemd (code=exited, status=0/SUCCESS)
     Main PID: 3547 (mysqld)
        Tasks: 27 (limit: 512)
       CGroup: /system.slice/mysqld.service
               └─3547 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid

首次启动后,查看 MySQL 日志找到 root 账户的临时密码:

[devalone@devalone mysql]$ sudo grep 'temporary password' /var/log/mysqld.log
    2018-07-16T04:11:08.456975Z 1 [Note] A temporary password is generated for root@localhost: 0I#ClXjke4F8

以 root 临时密码登录:

[devalone@devalone mysql]$ mysql -uroot -p
    Enter password:

输入查找到的临时密码登录到 MySQL 系统。登录之后第一件事就是修改 root 账户密码:

mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY '1235678';
    Query OK, 0 rows affected (0.00 sec)

退出 mysql,以新密码重新登录:

mysql> exit
    Bye

[devalone@devalone mysql]$ mysql -uroot -p
    Enter password:
    Welcome to the MySQL monitor.  Commands end with ; or \g.
    Your MySQL connection id is 5
    Server version: 5.7.19 MySQL Community Server (GPL)

2.1.2 使用 MySQL 数据库
-----------------------------------------------------------------------------------------------------------------------------------------
mysql 客户端程序允许通过用户账户和密码连到网络中任何地方的 MySQL 数据库服务器。默认情况下,如果在命令行上输入 mysql,且不加任何参数,它会
试图用 Linux 登录用户名连接运行在本地 Linux 系统上的 MySQL服务器。

通常还是创建一个应用程序专用的账户比较安全,不要用 MySQL 服务器上的 root 用户账户。这样可以针对应用程序用户实施访问限制,即便应用程序出现
问题,在必要时也可以删除或重建。可以使用 -u 参数指定登录用户名。

创建用户:
    mysql> CREATE USER 'devalone'@'%' IDENTIFIED BY '12345678' ;
    Query OK, 0 rows affected (0.00 sec)

2.1.2.1 mysql命令    
-----------------------------------------------------------------------------------------------------------------------------------------
mysql 程序使用两种不同类型的命令:

□ 特殊的mysql命令
    □ 标准SQL语句

mysql 程序使用它自有的一组命令,方便用户控制环境和提取关于 MySQL 服务器的信息。这些命令要么是全名(例如 status),要么是简写形式(例如\s)。
可以从 mysql 命令提示符中直接使用命令的完整形式或简形式。

示例:
    mysql> \s
    --------------
    mysql  Ver 14.14 Distrib 5.7.19, for Linux (x86_64) using  EditLine wrapper

Connection id:          5
    Current database:
    Current user:           root@localhost
    SSL:                    Not in use
    Current pager:          stdout
    Using outfile:          ''
    Using delimiter:        ;
    Server version:         5.7.19 MySQL Community Server (GPL)
    Protocol version:       10
    Connection:             Localhost via UNIX socket
    Server characterset:    latin1
    Db     characterset:    latin1
    Client characterset:    utf8
    Conn.  characterset:    utf8
    UNIX socket:            /var/lib/mysql/mysql.sock
    Uptime:                 34 min 19 sec

Threads: 1  Questions: 13  Slow queries: 0  Opens: 112  Flush tables: 1  Open tables: 105  Queries per second avg: 0.006
    --------------

mysql 程序实现了 MySQL 服务器支持的所有标准SQL(Structured Query Language,结构化查询语言)命令。mysql程序实现的一条 SQL 命令 SHOW,可以
利用这条命令提取 MySQL 服务器的相关信息,如创建的数据库和表:

mysql> SHOW DATABASES;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | sys                |
    +--------------------+
    4 rows in set (0.00 sec)

mysql> USE mysql;
    Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A

Database changed
    mysql> SHOW TABLES;
    +---------------------------+
    | Tables_in_mysql           |
    +---------------------------+
    | columns_priv              |
    | db                        |
    | engine_cost               |
    | event                     |
    | func                      |
    | general_log               |
    | gtid_executed             |
    | help_category             |
    | help_keyword              |
    | help_relation             |
    | help_topic                |
    | innodb_index_stats        |
    | innodb_table_stats        |
    | ndb_binlog_index          |
    | plugin                    |
    | proc                      |
    | procs_priv                |
    | proxies_priv              |
    | server_cost               |
    | servers                   |
    | slave_master_info         |
    | slave_relay_log_info      |
    | slave_worker_info         |
    | slow_log                  |
    | tables_priv               |
    | time_zone                 |
    | time_zone_leap_second     |
    | time_zone_name            |
    | time_zone_transition      |
    | time_zone_transition_type |
    | user                      |
    +---------------------------+
    31 rows in set (0.00 sec)

在这个例子中,用 SQL 命令 SHOW 来显示当前在 MySQL 服务器上配置过的数据库,然后用 SQL 命令 USE 来连接到单个数据库。mysql 会话一次只能连一个
数据库。

在每个命令后面都加一个分号。在 mysql 程序中,分号(或者 \g)表明命令的结束。如果不用分号,它会提示输入更多数据。

在处理长命令时,这个功能很有用。可以在一行输入命令的一部分,按下回车键,然后在下一行继续输入。这样一条命令可以占任意多行,直到用分号表明
命令结束。

2.1.2.2 创建数据库    
-----------------------------------------------------------------------------------------------------------------------------------------
MySQL 服务器将数据组织成数据库。数据库通常保存着单个应用程序的数据,与用这个数据库服务器的其他应用互不相关。为每个 shell 脚本应用创建一个
单独的数据库有助于避免数据混用。

创建一个新的数据库要用如下 SQL 语句:

CREATE DATABASE name;

示例:
    mysql> CREATE DATABASE mytest;
    Query OK, 1 row affected (0.01 sec)

mysql> SHOW DATABASES;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | mytest             |
    | performance_schema |
    | sys                |
    +--------------------+
    5 rows in set (0.00 sec)

2.1.2.3 创建用户账户    
-----------------------------------------------------------------------------------------------------------------------------------------
一直以 root 管理员账户连接到 MySQL 服务器。这个账户可以完全控制所有的 MySQL 服务器对象。在普通应用中使用 MySQL 的 root 账户是极其危险的。
如果有安全漏洞或有人弄到了 root 用户账户的密码,各种糟糕事情都可能发生在系统(以及数据)上。

为了阻止这种情况的发生,明智的做法是在 MySQL 上创建一个仅对应用中所涉及的数据库有权限的独立用户账户。可以用 GRANT SQL 语句来完成对已创建
账户的授权,也可以一次性完成创建用户及授权。

授权:
    GRANT privileges ON databasename.tablename TO 'username'@'host'
    
创建账户并授权:
    GRANT privileges ON databasename.tablename TO 'username'@'host' IDENTIFIED BY 'password'

示例:

mysql> GRANT CREATE,SELECT,INSERT,DELETE,UPDATE ON mytest.* TO 'devalone'@'%';
    Query OK, 0 rows affected (0.00 sec)

第一部分定义了用户账户对数据库有哪些权限。这条语句允许用户查询数据库数据(select权限)、插入新的数据记录以及删除和更新已有数据记录。

test.* 项定义了权限作用的数据库和表。通过下面的格式指定:

database.table

在指定数据库和表时可以使用通配符。这种格式会将指定的权限作用在名为 test 的数据库中的所有表上。

最后,你可以指定这些权限应用于哪些用户账户。grant 命令的便利之处在于,如果用户账户不存在,它会创建。IDENTIFIED BY 部分允许为新用户账户设定
默认密码。

可以直接在 mysql 程序中测试新用户账户:

[devalone@devalone mysql]$ mysql mytest -u devalone -p
    Enter password:
    Welcome to the MySQL monitor.  Commands end with ; or \g.
    Your MySQL connection id is 8
    Server version: 5.7.19 MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
    affiliates. Other names may be trademarks of their respective
    owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

第一个参数指定使用的默认数据库(mytest),-u 选项定义了登录的用户,-p 用来提示输入密码。输入 devalone 用户账户的密码后,就连到了服务器。

2.1.2.4 创建数据表    
-----------------------------------------------------------------------------------------------------------------------------------------
MySQL 是一种关系数据库(relational database)。在关系数据库中,数据按照字段、记录和表进行组织。数据字段是信息的单个组成部分,比如员工的姓
或工资。记录是相关数据字段的集合,比如员工ID号、姓、名、地址和工资。每条记录都代表一组数据字段。

表含有保存相关数据的所有记录。可以用一个 Employees 表来保存每个员工的记录:

要在数据库中新建一张新表,使用 SQL 的 CREATE TABLE 命令:

mysql> CREATE TABLE employees (
        -> empid int not null,
        -> lastname varchar(30),
        -> firstname varchar(30),
        -> salary float,
        -> primary key (empid));
    Query OK, 0 rows affected (0.25 sec)

mysql> SHOW TABLES ;
    +------------------+
    | Tables_in_mytest |
    +------------------+
    | employees        |
    +------------------+
    1 row in set (0.00 sec)

2.1.2.5 插入和删除数据    
-----------------------------------------------------------------------------------------------------------------------------------------
使用 SQL 命令 INSERT 语句向表中插入新的记录。每条 INSERT 语句都必须指定数据字段值来供 MySQL 服务器接受该记录。

INSERT 语句格式如下:

INSERT INTO table VALUES (...)

每个数据字段的值都用逗号分开。

mysql> INSERT INTO employees VALUES (1, 'Blum', 'Rich', 25000.00);
    Query OK, 1 row affected (0.06 sec)

要从表中删除数据,可以用 SQL 命令 DELETE 语句:

DELETE FROM table;

其中 table 指定了要从中删除记录的表。这个命令有个小问题:它会删除该表中所有记录。

要想只删除其中一条或多条数据行,必须用 WHERE 子句。WHERE 子句允许创建一个过滤器来指定删除哪些记录。

示例:

mysql> DELETE FROM employees WHERE empid = 2;
    Query OK, 1 row affected (0.04 sec)

2.1.2.6 查询数据    
-----------------------------------------------------------------------------------------------------------------------------------------
所有查询都是用 SQL 命令 SELECT 语句来完成。SELECT命令非常强大,但用起来也很复杂。

SELECT 语句的基本格式如下:

SELECT datafields FROM table

datafields 参数是一个用逗号分开的数据字段名称列表,指明了希望查询返回的字段。如果要提取所有的数据字段值,可以用星号*作通配符。

示例:
    mysql> SELECT * FROM employees;
    +-------+----------+------------+--------+
    | empid | lastname | firstname  | salary |
    +-------+----------+------------+--------+
    |     1 | Blum     | Rich       |  25000 |
    |     2 | Blum     | Barbara    |  45000 |
    |     3 | Blum     | Katie Jane |  34500 |
    |     4 | Blum     | Jessica    |  52340 |
    +-------+----------+------------+--------+
    4 rows in set (0.00 sec)

可以用一个或多个修饰符定义数据库服务器如何返回查询数据。下面列出了常用的修饰符:

□ WHERE        :显示符合特定条件的数据行子集。
    □ ORDER BY    :以指定顺序显示数据行。
    □ LIMIT        :只显示数据行的一个子集。

WHERE 子句是最常用的 SELECT 语句修饰符。它允许你指定查询结果的过滤条件。

示例:
    mysql> SELECT * FROM employees WHERE salary > 40000;
    +-------+----------+-----------+--------+
    | empid | lastname | firstname | salary |
    +-------+----------+-----------+--------+
    |     2 | Blum     | Barbara   |  45000 |
    |     4 | Blum     | Jessica   |  52340 |
    +-------+----------+-----------+--------+
    2 rows in set (0.00 sec)

MySQL 作为成功的典型开源关系型数据库系统,具有丰富数据管理能力,详细信息参考其官网专业文档:

https://dev.mysql.com/doc/

2.1.3 在脚本中使用数据库    
-----------------------------------------------------------------------------------------------------------------------------------------
现在已经有了一个可以正常工作的数据库,可以将精力放回 shell 脚本编程了。

2.1.3.1 登录到服务器    
-----------------------------------------------------------------------------------------------------------------------------------------
如果为自己的 shell 脚本在 MySQL 中创建了一个特定的用户账户,需要使用 mysql命令,以该用户的身份登录。实现的方法有好几种,其中一种是使用 -p
选项,在命令行中加入密码:

mysql mytest -u devalone –p 12345678

不过这并不是一个好做法。所有能够访问脚本的人都会知道数据库的用户账户和密码。

要解决这个问题,可以借助 mysql 程序所使用的一个特殊配置文件。mysql 程序使用 $HOME/.my.cnf 文件来读取特定的启动命令和设置。其中一项设置是
用户启动的 mysql 会话的默认密码。

[devalone@devalone ~]$ cat .my.cnf
    [client]
    password = 12345678
    [devalone@devalone ~]$ chmod 400 .my.cnf

可以使用 chmod 命令将 .my.cnf文件限制为只能由本人浏览。

测试登录:

[devalone@devalone ~]$ mysql mytest -u test
    Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A
    ...

这样就不用在 shell 脚本中将密码写在命令行上了。

2.1.3.2 向服务器发送命令    
-----------------------------------------------------------------------------------------------------------------------------------------
在建立起到服务器的连接后,接着就可以向数据库发送命令进行交互。有两种实现方法:

□ 发送单个命令并退出;
    □ 发送多个命令。
    
要发送单个命令,必须将命令作为 mysql 命令行的一部分。对于 mysql 命令,可以用 -e 选项。

示例:
    [devalone@devalone 25]$ cat mtest1.sh
    #!/bin/bash
    # send a command to the MySQL server
    MYSQL=$(which mysql)
    $MYSQL mytest -u devalone -p -e 'select * from employees'

运行:
    [devalone@devalone 25]$ ./mtest1.sh
    Enter password:
    +-------+----------+------------+--------+
    | empid | lastname | firstname  | salary |
    +-------+----------+------------+--------+
    |     1 | Blum     | Rich       |  25000 |
    |     2 | Blum     | Barbara    |  45000 |
    |     3 | Blum     | Katie Jane |  34500 |
    |     4 | Blum     | Jessica    |  52340 |
    +-------+----------+------------+--------+

数据库服务器会将 SQL 命令的结果返回给 shell 脚本,脚本会将它们显示在 STDOUT 中。

如果需要发送多条 SQL 命令,可以利用文件重定向。要在 shell 脚本中重定向多行内容,就必须定义一个结束(end of file)字符串。结束字符串指明了
重定向数据的开始和结尾。

示例:
    [devalone@devalone 25]$ cat mtest2.sh
    #!/bin/bash
    # sending multiple commands to MySQL
    MYSQL=$(which mysql)
    $MYSQL mytest -u devalone -p <<EOF
    show tables;
    select * from employees where salary > 40000;
    EOF

运行:
    [devalone@devalone 25]$ ./mtest2.sh
    Enter password:
    Tables_in_mytest
    employees
    empid   lastname        firstname       salary
    2       Blum    Barbara 45000
    4       Blum    Jessica 52340

shell 会将 EOF分隔符之间的所有内容都重定向给 mysql 命令。mysql 命令会执行这些命令行,就像你在提示符下亲自输入的一样。用了这种方法,可以
根据需要向 MySQL 服务器发送任意多条命令。

可以在脚本中使用任何类型的 SQL 命令,如 INSERT 语句。

示例:

[devalone@devalone 25]$ cat mtest3.sh
#!/bin/bash
# send data to the table in the MySQL database
MYSQL=$(which mysql)
if [ $# -ne 4 ]
then
        echo "Usage: mtest3 empid lastname firstname salary"
else
        statement="INSERT INTO employees VALUES ($1, '$2', '$3', $4)"
        $MYSQL mytest -u devalone -p << EOF
$statement
EOF
        if [ $? -eq 0 ]
        then
                echo Data successfully added
        else
                echo Problem adding data
        fi
fi

运行:
    [devalone@devalone 25]$ ./mtest3.sh
    Usage: mtest3 empid lastname firstname salary
    [devalone@devalone 25]$ ./mtest3.sh 5 Blum Jasper 100000
    Enter password:
    Data successfully added

这个例子演示了使用这种方法的一些注意事项。在指定结束字符串时,它必须是该行唯一的内容,并且该行必须以这个字符串开头。如果将 EOF 文本缩进
以和其余的 if-then 缩进对齐,它就不会起作用了。

注意,在 INSERT语句里,在文本值周围用了单引号,在整个 INSERT 语句周围用了双引号。一定不要弄混引用字符串值的引号和定义脚本变量文本的引号。

还有,使用 $? 特殊变量来测试 mysql 程序的退出状态码的。它有助于判断命令是否成功执行。

2.1.3.3 格式化数据    
-----------------------------------------------------------------------------------------------------------------------------------------
mysql 命令的标准输出并不太适合提取数据。如果要对提取到的数据进行处理,需要做一些特别的操作。

提取数据库数据的第一步是将 mysql 命令的输出重定向到一个环境变量中。可以在其他命令中使用输出信息。

示例:
    [devalone@devalone 25]$ cat mtest4.sh
    #!/bin/bash
    # redirecting SQL output to a variable
    MYSQL=$(which mysql)
    dbs=$($MYSQL mytest -u devalone -p -Bse 'show databases')
    for db in $dbs
    do
            echo $db
    done

运行:
    [devalone@devalone 25]$ ./mtest4.sh
    Enter password:
    information_schema
    mytest

这个例子在 mysql 程序的命令行上用了两个额外参数。-B 选项指定 mysql 程序工作在批处理模式运行,-s(silent)选项用于禁止输出列标题和格式化
符号。

通过将 mysql 命令的输出重定向到一个变量,此例可以逐步输出每条返回记录里的每个值。

mysql 程序还支持另外一种可扩展标记语言(Extensive Markup Language,XML)的流行格式。这种语言使用和 HTML类似的标签来标识数据名和值。

对于 mysql 程序,可以用 -X 命令行选项来输出。

示例:
    [devalone@devalone 25]$ mysql mytest -u devalone -p -X -e 'SELECT * FROM employees WHERE empid=1'
    Enter password:
    <?xml version="1.0"?>

<resultset statement="SELECT * FROM employees WHERE empid=1
    " xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <row>
            <field name="empid">1</field>
            <field name="lastname">Blum</field>
            <field name="firstname">Rich</field>
            <field name="salary">25000</field>
      </row>
    </resultset>

2.2 使用 Web
-----------------------------------------------------------------------------------------------------------------------------------------
作为一款于1992年由堪萨斯大学的学生编写的基于文本的浏览器,Lynx 程序的历史几乎和互联网一样悠久。因为该浏览器是基于文本的,所以它可以直接从
终端会话中访问网站,只不过 Web 页面上的那些漂亮图片被替换成了 HTML 文本标签。这样就可以在几乎所有类型的 Linux 终端上浏览互联网了。

Lynx 使用标准键盘按键浏览网页。链接会在Web页面上以高亮文本的形式出现。使用向右方向键可以跟随一个链接到下一个Web页面。

Lynx程序还提供了一个功能,允许将 Web 页面的文本内容转储到 STDOUT 中。这个功能非常适合用来挖掘 Web 页面中包含的数据。

多个知名的搜索引擎利用 lynx 协助工作,如下所示(2014-1-10 统计):

□ Ask.com
    □ Baidu (Chinese)
    □ Bing
    □ Dogpile
    □ goo (Japanese)
    □ Google
    □ Hakia
    □ IceRocket
    □ Indeed
    □ Lexxe
    □ Rambler (Russian)
    □ Search.com
    □ WebCrawler
    □ Yahoo!

可见,lynx 的实用价值是非常高的。

2.2.1 安装 Lynx
-----------------------------------------------------------------------------------------------------------------------------------------
尽管 Lynx 程序有点古老,但它的开发仍然很活跃。Lynx 的最新版本是 2018 年7月8日发布的 v2.8.9,新版本 2.9.0 正在研发中。其主页网址:

http://lynx.invisible-island.net/

鉴于 Lynx 在 shell 脚本程序员中十分流行,许多 Linux 发行版都将它作为默认程序安装。如果未安装,使用当前系统的包管理器安装。

下面是 Fedora 24 的安装指令:

[devalone@devalone ~]$ sudo dnf install lynx

2.2.2 lynx 命令行
-----------------------------------------------------------------------------------------------------------------------------------------
lynx 命令行命令极其擅长从远程网站上提取信息。当用浏览器查看 Web页面时,只是看到了传送到浏览器中信息的一部分。Web页面由三种类型的数据组成:

□ HTTP头部
    □ cookie
    □ HTML内容

HTTP 头部提供了连接中传送的数据类型、发送数据的服务器以及采用的连接安全类型的相关信息。如果发送的是特殊类型的数据,比如视频或音频剪辑,
服务器会将其在 HTTP 头部中标示出来。Lynx 程序允许查看 Web 页面会话中发送的所有 HTTP 头部。

网站用 cookie 存储有关网站的访问数据,以供将来使用。每个站点都能存储信息,但只能访问它自己设置的信息。lynx 命令提供了一些选项来查看 Web
服务器发送的 cookie,还可以接受或拒绝服务器发过来的特定 cookie。

Lynx 程序支持三种不同的格式来查看 Web 页面实际的 HTML 内容:

□ 在终端会话中利用 curses 图形库显示文本图形;
    □ 文本文件,文件内容是从 Web 页面中转储的原始数据;
    □ 文本文件,文件内容是从 Web 页面中转储的原始 HTML 源码。

对于 shell脚本,原始数据或 HTML 源码可是一座金山。一旦获得了从网站上检索到的信息,就能轻松地从中提取每一条信息。

Lynx 程序将它的本职工作发挥到了极致。但随之而来的是复杂性,尤其是对命令行参数来说。Lynx 程序是 Linux 世界中较复杂的程序之一。

lynx 命令的基本格式如下:

lynx options [URL | File]

其中 URL 是要连接的 HTTP 或 HTTPS 地址,options 则是一个或多个选项。这些选项可以在 Lynx 与远程网站交互时改变它的行为。许多命令行参数定义
了 Lynx 的行为,可以用来控制全屏模式下的 Lynx,允许在浏览 Web 页面时对其进行定制。

通过 lynx -help 命令获取更完整的帮助信息:

[devalone@devalone wpan123.com]$ lynx -help
USAGE: lynx [options] [file]
Options are:
  -                 receive options and arguments from stdin
  -accept_all_cookies
                    accept cookies without prompting if Set-Cookie handling
                    is on (off)
  -anonymous        apply restrictions for anonymous account,
                    see also -restrictions
  -assume_charset=MIMEname
                    charset for documents that don't specify it
  -assume_local_charset=MIMEname
                    charset assumed for local files
  -assume_unrec_charset=MIMEname
                    use this instead of unrecognized charsets
  -auth=id:pw       authentication information for protected documents
  -base             prepend a request URL comment and BASE tag to text/html
                    outputs for -source dumps
  -bibhost=URL      local bibp server (default http://bibhost/)
  -book             use the bookmark page as the startfile (off)
  -buried_news      toggles scanning of news articles for buried references (on)
  -cache=NUMBER     NUMBER of documents cached in memory
  -case             enable case sensitive user searching (off)
  -center           toggle center alignment in HTML TABLE (off)
  -cfg=FILENAME     specifies a lynx.cfg file other than the default
  -child            exit on left-arrow in startfile, and disable save to disk
  -child_relaxed    exit on left-arrow in startfile (allows save to disk)
  -cmd_log=FILENAME log keystroke commands to the given file
  -cmd_script=FILENAME
                    read keystroke commands from the given file
                    (see -cmd_log)
  -connect_timeout=N
                    set the N-second connection timeout (18000)
  -cookie_file=FILENAME
                    specifies a file to use to read cookies
  -cookie_save_file=FILENAME
                    specifies a file to use to store cookies
  -cookies          toggles handling of Set-Cookie headers (on)
  -core             toggles forced core dumps on fatal errors (off)
  -crawl            with -traversal, output each page to a file
                    with -dump, format output as with -traversal, but to stdout
  -curses_pads      uses curses pad feature to support left/right shifting (on)
  -debug_partial    incremental display stages with MessageSecs delay (off)
  -default_colors   use terminal default foreground/background colors (on)
  -delay=NNN        set NNN-second delay at statusline message (0.000)
  -display=DISPLAY  set the display variable for X exec'ed programs
  -display_charset=MIMEname
                    charset for the terminal output
  -dont_wrap_pre    inhibit wrapping of text in <pre> when -dump'ing and
                    -crawl'ing, mark wrapped lines in interactive session (off)
  -dump             dump the first file to stdout and exit
  -editor=EDITOR    enable edit mode with specified editor
  -emacskeys        enable emacs-like key movement (off)
  -enable_scrollback
                    toggles compatibility with comm programs' scrollback
                    keys (may be incompatible with some curses packages) (off)
  -error_file=FILE  write the HTTP status code here
  -force_empty_hrefless_a
                    force HREF-less 'A' elements to be empty (close them as
                    soon as they are seen) (off)
  -force_html       forces the first document to be interpreted as HTML (off)
  -force_secure     toggles forcing of the secure flag for SSL cookies (off)
  -forms_options    toggles forms-based vs old-style options menu (on)
  -from             toggle transmission of From headers (on)
  -ftp              disable ftp access (off)
  -get_data         user data for get forms, read from stdin,
                    terminated by '---' on a line
  -head             send a HEAD request (off)
  -help             print this usage message
  -hiddenlinks=[option]
                    hidden links: options are merge, listonly, or ignore
  -historical       toggles use of '>' or '-->' as terminator for comments (off)
  -homepage=URL     set homepage separate from start page
  -html5_charsets   toggles use of HTML5 charset replacements (off)
  -image_links      toggles inclusion of links for all images (off)
  -index=URL        set the default index file to URL
  -ismap            toggles inclusion of ISMAP links when client-side
                    MAPs are present (off)
  -justify          do justification of text (off)
  -link=NUMBER      starting count for lnk#.dat files produced by -crawl (0)
  -list_inline      with -dump, forces it to show links inline with text (off)
  -listonly         with -dump, forces it to show only the list of links (off)
  -localhost        disable URLs that point to remote hosts (off)
  -lss=FILENAME     specifies a lynx.lss file other than the default
  -mime_header      include mime headers and force source dump
  -minimal          toggles minimal versus valid comment parsing (on)
  -newschunksize=NUMBER
                    number of articles in chunked news listings
  -newsmaxchunk=NUMBER
                    maximum news articles in listings before chunking
  -nobold           disable bold video-attribute
  -nobrowse         disable directory browsing
  -nocc             disable Cc: prompts for self copies of mailings (off)
  -nocolor          turn off color support
  -nofilereferer    disable transmission of Referer headers for file URLs (on)
  -nolist           disable the link list feature in dumps (off)
  -nolog            disable mailing of error messages to document owners (on)
  -nomargins        disable the right/left margins in the default
                    style-sheet (off)
  -nomore           disable -more- string in statusline messages
  -nonrestarting_sigwinch
                    make window size change handler non-restarting (off)
  -nonumbers        disable the link/form numbering feature in dumps (off)
  -nopause          disable forced pauses for statusline messages
  -noprint          disable some print functions, like -restrictions=print (off)
  -noredir          don't follow Location: redirection (off)
  -noreferer        disable transmission of Referer headers (off)
  -noreverse        disable reverse video-attribute
  -nostatus         disable the miscellaneous information messages (off)
  -notitle          disable the title at the top of each page (off)
  -nounderline      disable underline video-attribute
  -number_fields    force numbering of links as well as form input fields (off)
  -number_links     force numbering of links (off)
  -partial          toggles display partial pages while downloading (on)
  -partial_thres    [=NUMBER]
                    number of lines to render before repainting display
                    with partial-display logic (-1)
  -passive-ftp      toggles passive ftp connection (on)
  -pauth=id:pw      authentication information for protected proxy server
  -popup            toggles handling of single-choice SELECT options via
                    popup windows or as lists of radio buttons (off)
  -post_data        user data for post forms, read from stdin,
                    terminated by '---' on a line
  -preparsed        show parsed text/html with -source and in source view
                    to visualize how lynx behaves with invalid HTML (off)
  -prettysrc        do syntax highlighting and hyperlink handling in source
                    view (off)
  -print            enable print functions (DEFAULT), opposite of -noprint (on)
  -pseudo_inlines   toggles pseudo-ALTs for inlines with no ALT string (on)
  -raw              toggles default setting of 8-bit character translations
                    or CJK mode for the startup character set (off)
  -realm            restricts access to URLs in the starting realm (off)
  -read_timeout=N   set the N-second read-timeout (18000)
  -reload           flushes the cache on a proxy server
                    (only the first document affected) (off)
  -restrictions=[options]
                    use -restrictions to see list
  -resubmit_posts   toggles forced resubmissions (no-cache) of forms with
                    method POST when the documents they returned are sought
                    with the PREV_DOC command or from the History List (off)
  -rlogin           disable rlogins (off)
  -scrollbar        toggles showing scrollbar (off)
  -scrollbar_arrow  toggles showing arrows at ends of the scrollbar (on)
  -selective        require .www_browsable files to browse directories
  -session=FILENAME resumes from specified file on startup and
                    saves session to that file on exit
  -sessionin=FILENAME
                    resumes session from specified file
  -sessionout=FILENAME
                    saves session to specified file
  -short_url        enables examination of beginning and end of long URL in
                    status line (off)
  -show_cfg         Show `LYNX.CFG' setting (off)
  -show_cursor      toggles hiding of the cursor in the lower right corner (on)
  -show_rate        toggles display of transfer rate (on)
  -soft_dquotes     toggles emulation of the old Netscape and Mosaic
                    bug which treated '>' as a co-terminator for
                    double-quotes and tags (off)
  -source           dump the source of the first file to stdout and exit
  -stack_dump       disable SIGINT cleanup handler (off)
  -startfile_ok     allow non-http startfile and homepage with -validate (off)
  -stderr           write warning messages to standard error when -dump
                    or -source is used (off)
  -stdin            read startfile from standard input (off)
  -tagsoup          use TagSoup rather than SortaSGML parser (off)
  -telnet           disable telnets (off)
  -term=TERM        set terminal type to TERM
  -tlog             toggles use of a Lynx Trace Log for the current
                    session (on)
  -tna              turn on "Textfields Need Activation" mode (off)
  -trace            turns on Lynx trace mode (off)
  -trace_mask       customize Lynx trace mode (0)
  -traversal        traverse all http links derived from startfile
  -trim_input_fields
                    trim input text/textarea fields in forms (off)
  -underline_links  toggles use of underline/bold attribute for links (off)
  -underscore       toggles use of _underline_ format in dumps (off)
  -unique_urls      toggles use of unique-urls setting for -dump and -listonly options (off)
  -use_mouse        turn on mouse support (off)
  -useragent=Name   set alternate Lynx User-Agent header
  -validate         accept only http URLs (meant for validation)
                    implies more restrictions than -anonymous, but
                    goto is allowed for http and https (off)
  -verbose          toggles [LINK], [IMAGE] and [INLINE] comments
                    with filenames of these images (on)
  -version          print Lynx version information
  -vikeys           enable vi-like key movement (off)
  -width=NUMBER     screen width for formatting of dumps (default is 80)
  -with_backspaces  emit backspaces in output if -dumping or -crawling
                    (like 'man' does) (off)
  -xhtml-parsing    enable XHTML 1.0 parsing (off)

2.2.3 Lynx 配置文件
-----------------------------------------------------------------------------------------------------------------------------------------
在正常的浏览环境中,通常会发现有几组命令行参数非常有用。不用每次使用 Lynx 时都在命令行上将这些参数输入一遍,Lynx 提供了一个通用配置文件来
定义 Lynx 的基本行为。

lynx 命令会从配置文件中读取大量的参数设置。默认情况下, 这个文件位于 /usr/local/lib/lynx.cfg,不过有许多 Linux发行版将其改放到了/etc目录
下(/etc/lynx.cfg)(Ubuntu 发行版将 lynx.cfg 放到了 /etc/lynx-curl 目录中)。

使用命令行搜索:

[devalone@devalone ~]$ whereis lynx.cfg
    lynx: /usr/bin/lynx /etc/lynx.lss /etc/lynx.cfg /usr/share/man/man1/lynx.1.gz

当前系统 Fedora 24 位于 /etc/lynx.cfg

lynx.cfg 配置文件将相关的参数分组到不同的区域中,这样更容易找到参数。配置文件中条目的格式为:

PARAMETER:value
    
其中 PARAMETER 是参数的全名(通常都是用大写字母,但也不总是如此),value 是跟参数关联的值。

浏览一下这个文件,会发现许多参数都跟命令行参数类似,比如 ACCEPT_ALL_COOKIES 参数就等同于设置了 -accept_all_cookies 命令行参数。

还有一些配置参数功能类似,但名称不同。FORCE_SSL_COOKIES_SECURE 配置文件参数设置可以用 -force_secure 命令行参数将其覆盖掉。

还有少数配置参数并没有对应的命令行参数。这些值只能在配置文件中设定。

最常见的不能在命令行上设置的配置参数是代理服务器。有些网络(尤其是公司网络)使用代理服务器作为客户端浏览器和目标网站的桥梁。客户端浏览器
不能直接向远程 Web 服务器发送 HTTP 请求,而是必须将它们的请求发到代理服务器上,然后由代理服务器将请求转发给远程 Web服务器,获取结果,再将
结果回传给客户端浏览器。

用来定义代理服务器的配置参数有:

http_proxy:http://some.server.dom:port/
    https_proxy:http://some.server.dom:port/
    ftp_proxy:http://some.server.dom:port/
    gopher_proxy:http://some.server.dom:port/
    news_proxy:http://some.server.dom:port/
    newspost_proxy:http://some.server.dom:port/
    newsreply_proxy:http://some.server.dom:port/
    snews_proxy:http://some.server.dom:port/
    snewspost_proxy:http://some.server.dom:port/
    snewsreply_proxy:http://some.server.dom:port/
    nntp_proxy:http://some.server.dom:port/
    wais_proxy:http://some.server.dom:port/
    finger_proxy:http://some.server.dom:port/
    cso_proxy:http://some.server.dom:port/
    no_proxy:host.domain.dom

可以为任何 Lynx 支持的网络协议定义不同的代理服务器。NO_PROXY 参数是逗号分隔的网站列表。对于列表中的这些网站,不使用代理服务器而是直接访问。

2.2.4 从 Lynx 中获取数据
-----------------------------------------------------------------------------------------------------------------------------------------
在 shell 脚本中使用 Lynx 时,大多数情况下只是要提取 Web页面中的某条(或某几条)特定信息。完成这个任务的方法称作屏幕抓取(screen scraping)。
在屏幕抓取过程中,要尝试通过编程寻找图形化屏幕上某个特定位置的数据,这样才能获取它并在脚本中使用。

用 lynx 进行屏幕抓取的最简单办法是用 -dump 选项。这个选项不会在终端屏幕上显示 Web 页面。相反,它会将 Web 页面文本数据直接显示在STDOUT上。

示例: 查看 lynx 帮助主页面
    
[devalone@devalone ~]$ lynx -dump http://lynx.invisible-island.net/lynx_help/lynx_help_main.html
     __________________________________________________________________

[1]https://lynx.invisible-island.net/[2]lynx_help/
     __________________________________________________________________

* [3](top)
     * [4]Lynx Users Guide
     * [5]Key-stroke Commands
     * [6]Line Editor
     * [7]Supported URLs
     * About
          + [8]Lynx
          + [9]Lynx-Dev
     * Configuration
          + [10]by Category
          + [11]by Names

The Lynx Help Page – quick-links and detailed documentation

Lynx help files (usually in your local directories):

These Lynx documents are part of your local configuration:
     * [12]Lynx Users Guide — complete account of all Lynx features
     * [13]Key-stroke Commands — quick outline of what various keys do
     * [14]Line Editor — when entering URLs etc
     * [15]Supported URLs — how Lynx handles various types of URL
     * [16]About Lynx — credits, copyright etc
     * [17]About Lynx-Dev — the developers & how to contact them

Other sources of Lynx help:

The Lynx configuration guide may also be local.
     * [18]lynx.cfg options — a reference for advanced configurations
     * [19]lynx documentation — supplementary documentation
     * [20]Lynx Help for Beginners — quick help on many common problems
     * [21]Blynx — Speech-Friendly Help for the visually impaired

World Wide Web Consortium documents:

* HTML — [22]5.1 — [23]4.0 — [24]3.2 — [25]3.0 — [26]2.0
     * HTTP — [27]1.1 — [28]1.0
     * XHTML — [29]1.0
     * [30]Web Naming & Addressing Overview: URIs, URLs etc
     * [31]HTML Internationalization
     * [32]WWW Consortium: home page

Help with HTML:

* [33]HTML 4.0 Reference
     * [34]W3Schools
     * [35]HTML Goodies
     * [36]HTML Code Tutorial
     * [37]HTML Cheat Sheet – A Simple Guide to HTML

HTML validation services:

* [38]W3C HTML Validation Service
     * [39]WDG HTML Validator

Other browsing software:

* [40]GNU wget — powerful & flexible non-interactive downloader
     * [41]Pavuk — powerful & an even more-featured downloader
     * [42]cURL — non-interactive downloader which supports HTTPS
     * [43]snarf — small simple 1-file non-interactive downloader

Historical interest

* [44]NCSA Mosaic

Search engines:

These work with Lynx as of 2014/01/10:
     * [45]Ask.com
     * [46]Baidu (Chinese)
     * [47]Bing
     * [48]Dogpile
     * [49]goo (Japanese)
     * [50]Google
     * [51]Hakia
     * [52]IceRocket
     * [53]Indeed
     * [54]Lexxe
     * [55]Rambler (Russian)
     * [56]Search.com
     * [57]WebCrawler
     * [58]Yahoo!

References

Visible links
   1. http://lynx.invisible-island.net/
   2. http://lynx.invisible-island.net/lynx_help/lynx_help_main.html
   3. http://lynx.invisible-island.net/lynx_help/lynx_help_main.html
   4. http://lynx.invisible-island.net/lynx_help/Lynx_users_guide.html
   5. http://lynx.invisible-island.net/lynx_help/keystrokes/keystroke_help.html
   6. http://lynx.invisible-island.net/lynx_help/keystrokes/edit_help.html
   7. http://lynx.invisible-island.net/lynx_help/lynx_url_support.html
   8. http://lynx.invisible-island.net/lynx_help/about_lynx.html
   9. http://lynx.invisible-island.net/lynx_help/lynx-dev.html
  10. http://lynx.invisible-island.net/lynx_help/cattoc.html
  11. http://lynx.invisible-island.net/lynx_help/alphatoc.html
  12. http://lynx.invisible-island.net/lynx_help/Lynx_users_guide.html
  13. http://lynx.invisible-island.net/lynx_help/keystrokes/keystroke_help.html
  14. http://lynx.invisible-island.net/lynx_help/keystrokes/edit_help.html
  15. http://lynx.invisible-island.net/lynx_help/lynx_url_support.html
  16. http://lynx.invisible-island.net/lynx_help/about_lynx.html
  17. http://lynx.invisible-island.net/lynx_help/lynx-dev.html
  18. http://lynx.invisible-island.net/lynx_help/cattoc.html
  19. http://lynx.invisible-island.net/lynx_doc/
  20. http://www.chass.utoronto.ca/~purslow/lhfb.html
  21. http://leb.net/blinux/blynx/
  22. http://www.w3.org/TR/html51/
  23. http://www.w3.org/TR/REC-html40/
  24. http://www.w3.org/TR/REC-html32
  25. http://www.w3.org/MarkUp/html3/Contents.html
  26. http://www.w3.org/MarkUp/html-spec/html-spec_toc.html
  27. http://www.w3.org/Protocols/
  28. http://www.isi.edu/in-notes/rfc1945.txt
  29. http://www.w3.org/TR/xhtml1/
  30. http://www.w3.org/Addressing/
  31. http://www.w3.org/International/
  32. http://www.w3.org/
  33. http://www.htmlhelp.com/reference/html40/
  34. http://www.w3schools.com/html/default.asp
  35. http://www.htmlgoodies.com/primers/html/
  36. http://www.htmlcodetutorial.com/
  37. http://www.simplehtmlguide.com/cheatsheet.php
  38. http://validator.w3.org/
  39. http://www.htmlhelp.com/tools/validator/
  40. http://wget.addictivecode.org/
  41. http://www.pavuk.org/
  42. http://curl.haxx.se/
  43. http://www.xach.com/snarf/
  44. http://web.archive.org/web/2005050785333/http://archive.ncsa.uiuc.edu/SDG/Software/Mosaic/MetaIndex.html
  45. http://www.ask.com/
  46. http://www.baidu.com/
  47. http://www.bing.com/
  48. http://www.dogpile.com/
  49. http://labs.goo.ne.jp/
  50. http://www.google.com/
  51. http://hakia.com/
  52. http://www.icerocket.com/
  53. http://www.indeed.com/
  54. http://www.lexxe.com/
  55. http://www.rambler.ru/
  56. http://www.search.com/
  57. http://www.webcrawler.com/
  58. http://www.yahoo.com/

Hidden links:
  60. http://lynx.invisible-island.net/lynx_help/lynx_help_main.html

每个链接都由一个标号标定,Lynx 在 Web 页面数据后显示了所有标号所指向的 URL 地址。这正是搜索引擎喜欢 lynx 的原因,有了 URL 列表,抓取内容
就好了。

从 Web页面中获得了所有文本数据之后,可以利用 sed 编辑器和 gawk 程序来提取数据。

首先,找一些有意思的数据来收集。Yahoo!天气页面是找出全世界任何地区当前气候的不错来源。每个位置都用一个单独的 URL 来显示该城市的天气信息
(可以在浏览器中打开该站点并输入你的城市信息来获取所在地的特定 URL)。查看伊利诺伊州芝加哥市的天气情况的 lynx 命令如下:

lynx -dump http://weather.yahoo.com/united-states/illinois/chicago-2379574/ >weather-chicago.txt

这条命令会从页面中转储出很多的数据。第一步是找到需要的准确信息。要做到这点,需将 lynx 命令的输出重定向到一个文件中,本例重定向到文本文件
weather-chicago.txt,然后在文件中查找数据。

查看文件: 利用 cat -n 选项打印出行号,便于处理

[devalone@devalone 25]$ cat -n weather-chicago.txt
     1       * Home
     2       * [1]Mail
     3       * [2]Tumblr
     4       * [3]News
     5       * [4]Sports
     6       * [5]Finance
     7       * [6]Entertainment
     8       * [7]Lifestyle
     9       * [8]Answers
    10       * [9]Groups
    11       * [10]Mobile
    12       * [11]More
    13
    14     [12]Yahoo
    15     Search
    16     ____________________
    17
    18     (BUTTON) Search
    19       *
    20       *
    21
    22     The forecast is beautiful
    23     Get the App
    24
    25  My Locations
    26
    27       Click star button to save cities
    28
    29  Around the World
    30
    31       * [13]New York
    32       * [14]Los Angeles
    33       * [15]Chicago
    34       * [16]Houston
    35       * [17]Philadelphia
    36       * [18]San Francisco
    37       * [19]Mexico City
    38       * [20]Tokyo
    39       * [21]Sao Paulo
    40       * [22]London
    41       * [23]Paris
    42       * [24]Venice
    43
    44  Chicago
    45
    46     United States
    47     (BUTTON)
    48     (BUTTON)
    49     Change location
    50     Fair Mostly Clear
    51     86°
    52     67°
    53     72°
    54     (BUTTON) F (BUTTON) C
    55     [25]© by teekay72 on
    56
    57  Forecast
    58
    59     [Temperature__]
    60       * 12 AM Fair 72°
    61       * 1 AM Clear 71°
    62       * 2 AM Clear 71°
    63       * 3 AM Clear 70°
    64       * 4 AM Clear 70°
    65       * 5 AM Clear 70°
    66       * 6 AM Sunny 71°
    67       * 7 AM Sunny 72°
    68       * 8 AM Fair 74°
    69       * 9 AM Fair 74°
    70       * 10 AM Partly Cloudy 75°
    71       * 11 AM Partly Cloudy 76°
    72       * 12 PM Partly Cloudy 76°
    73       * 1 PM Partly Cloudy 76°
    74       * 2 PM Fair 76°
    75       * 3 PM Fair 75°
    76       * 4 PM Sunny 75°
    77       * 5 PM Sunny 74°
    78       * 6 PM Sunny 73°
    79       * 7 PM Sunny 72°
    80       * 8 PM Sunny 71°
    81       * 9 PM Clear 70°
    82       * 10 PM Clear 69°
    83       * 11 PM Clear 68°
    84       * 12 AM Clear 68°
    85
    86     Monday
    87     Thunderstorms Precipitation: 100% 100%86°67°Night - Clear. Winds
    88     variable at 7 to 11 mph (11.3 to 17.7 kph). The overnight low will be
    89     70 °F (21.1 °C).Partly cloudy with a high of 76 °F (24.4 °C). Winds
    90     variable at 9 to 11 mph (14.5 to 17.7 kph).
    91     Tuesday
    92     Sunny Precipitation: 0% 0%76°68°Sunny today with a high of 76 °F (24.4
    93     °C) and a low of 68 °F (20.0 °C).
    94     Wednesday
    95     Fair Precipitation: 0% 0%74°66°Mostly sunny today with a high of 74 °F
    96     (23.3 °C) and a low of 66 °F (18.9 °C).
    97     Thursday
    98     Mostly Cloudy Precipitation: 15% 15%80°66°Mostly cloudy today with a
    99     high of 80 °F (26.7 °C) and a low of 66 °F (18.9 °C).
   100     Friday
   101     Thunderstorms Precipitation: 25% 25%80°71°Thunderstorms today with a
   102     high of 80 °F (26.7 °C) and a low of 71 °F (21.7 °C). There is a 25%
   103     chance of precipitation.
   104     Saturday
   105     Partly Cloudy Precipitation: 15% 15%77°69°Partly cloudy today with a
   106     high of 77 °F (25.0 °C) and a low of 69 °F (20.6 °C).
   107     Sunday
   108     Partly Cloudy Precipitation: 10% 10%75°69°Partly cloudy today with a
   109     high of 75 °F (23.9 °C) and a low of 69 °F (20.6 °C).
   110     Monday
   111     Partly Cloudy Precipitation: 5% 5%75°69°Partly cloudy today with a high
   112     of 75 °F (23.9 °C) and a low of 69 °F (20.6 °C).
   113     Tuesday
   114     Partly Cloudy Precipitation: 5% 5%81°68°Partly cloudy today with a high
   115     of 81 °F (27.2 °C) and a low of 68 °F (20.0 °C).
   116     Wednesday
   117     Partly Cloudy Precipitation: 5% 5%75°67°Partly cloudy today with a high
   118     of 75 °F (23.9 °C) and a low of 67 °F (19.4 °C).
   119     (BUTTON) 5 day (BUTTON) 10 day
   120
   121  Precipitation
   122
   123     Overnight
   124     Early Morning
   125     Morning
   126     Afternoon
   127     Precipitation: 0% 0%
   128     Precipitation: 0% 0%
   129     Precipitation: 0% 0%
   130     Precipitation: 0% 0%
   131
   132  Wind & Pressure
   133
   134     Wind
   135
   136     4 mph NW
   137     Barometer
   138
   139     29.4 inches
   140
   141  Details
   142
   143     Fair
   144       * Feels like
   145         77°
   146       * Humidity
   147         85%
   148       * Visibility
   149         10.00 miles
   150       * UV Index
   151         0 (Low)
   152
   153     Tonight - Clear. Winds variable at 7 to 11 mph (11.3 to 17.7 kph). The
   154     overnight low will be 70 °F (21.1 °C).
   155
   156     Today - Partly cloudy with a high of 76 °F (24.4 °C). Winds variable at
   157     9 to 11 mph (14.5 to 17.7 kph).
   158
   159  Sun & Moon
   160
   161     Waxing Crescent
   162     Waxing Crescent
   163     5:29 AM8:24 PM
   164
   165  Map
   166
   167     Satellite
   168     (BUTTON) [spaceball.gif] (BUTTON) [spaceball.gif] (BUTTON)
   169     [spaceball.gif]
   170     [26]View interactive map
   171
   172  References
   173
   174     Visible links
   175     1. https://mail.yahoo.com/?.intl=us&.lang=en-US
   176     2. https://www.tumblr.com/
   177     3. https://www.yahoo.com/news/
   178     4. http://sports.yahoo.com/
   179     5. http://finance.yahoo.com/
   180     6. https://www.yahoo.com/entertainment/
   181     7. https://www.yahoo.com/lifestyle/
   182     8. https://answers.yahoo.com/
   183     9. https://groups.yahoo.com/
   184    10. https://mobile.yahoo.com/
   185    11. https://everything.yahoo.com/
   186    12. https://www.yahoo.com/news/
   187    13. https://www.yahoo.com/news/weather/united-states/new-york/new-york-2459115
   188    14. https://www.yahoo.com/news/weather/united-states/california/los-angeles-2442047
   189    15. https://www.yahoo.com/news/weather/united-states/illinois/chicago-2379574
   190    16. https://www.yahoo.com/news/weather/united-states/texas/houston-2424766
   191    17. https://www.yahoo.com/news/weather/united-states/pennsylvania/philadelphia-2471217
   192    18. https://www.yahoo.com/news/weather/united-states/california/san-francisco-2487956
   193    19. https://www.yahoo.com/news/weather/mexico/distrito-federal/mexico-city-116545
   194    20. https://www.yahoo.com/news/weather/japan/tokyo-prefecture/tokyo-1118370
   195    21. https://www.yahoo.com/news/weather/brazil/sao-paulo/sao-paulo-455827
   196    22. https://www.yahoo.com/news/weather/united-kingdom/england/london-44418
   197    23. https://www.yahoo.com/news/weather/france/île-de-france/paris-615702
   198    24. https://www.yahoo.com/news/weather/italy/veneto/venice-725746
   199    25. https://www.flickr.com/photos/42198058@N04/10901600376
   200    26. http://weather.com/weather/radar/interactive/l/41.88,-87.63
   201
   202     Hidden links:
   203    28. https://www.yahoo.com/
   204    29. https://mail.yahoo.com/?.intl=us&.lang=en-US&.partner=none&.src=weather
   205    30. https://mobile.yahoo.com/weather/

其中:
    44  Chicago
    45
    46     United States
    47     (BUTTON)
    48     (BUTTON)
    49     Change location
    50     Fair Mostly Clear
    51     86°
    52     67°
    53     72°
    
是当前的气温和最高最低值,华氏温度值。
    
下面内容为详细信息:
    
   141  Details
   142
   143     Fair
   144       * Feels like
   145         77°
   146       * Humidity
   147         85%
   148       * Visibility
   149         10.00 miles
   150       * UV Index
   151         0 (Low)

这都是需要的关于当前天气的所有信息。但这段输出中有个小问题。数字都是在标题下面一行的。只提取单独的数字有些困难。

解决这一问题的关键是先写一个能查找数据标题的 sed 脚本。找到之后,就可以到正确的行中提取数据了。这个例子中所需要的数据就是那些文本行。只用
sed 脚本就能解决了。如果在同一行中还有其他文本,就需要使用 gawk 工具来过滤出我们需要的数据。

创建一个 sed 脚本打印描述当前天气状况的文本(51,53)。输出芝加哥天气的脚本如下:

[devalone@devalone 25]$ cat sedcond.sed
    51,53p

下一步,需要一段 sed 脚本来查找文本Feels Like,并打印出下一行的温度:

[devalone@devalone 25]$ cat sedtemp.sed
    145p

现在可以在 shell 脚本中用这两个 sed 脚本。首先将 Web 页面的 lynx 输出放入一个临时文件中,然后对 Web 页面数据使用这两个sed脚本,提取所需的
数据:

[devalone@devalone 25]$ cat weather.sh
    #!/bin/bash
    # extract the current weather for Chicago, IL

URL="http://weather.yahoo.com/united-states/illinois/chicago-2379574/"
    LYNX=$(which lynx)
    TMPFILE=$(mktemp tmpXXXXXX)

$LYNX -dump $URL > $TMPFILE
    addr=$(cat $TMPFILE | sed -n '44p')
    conditions=$(cat $TMPFILE | sed -n -f sedcond.sed)

temp=$(cat $TMPFILE | sed -n -f sedtemp.sed)

rm -f $TMPFILE

echo
    echo "Address: $addr"
    echo "Current conditions: "
    echo "$conditions"
    echo The current temp outside is: $temp

运行:
    [devalone@devalone 25]$ sh weather.sh

Address: Chicago
    Current conditions:
       76°
       63°
       63°
    The current temp outside is: 63°

weather.sh 脚本连接到指定城市的Yahoo!天气页面,将 Web 页面保存到一个文件中,提取对应的文本,删除临时文件,然后显示天气信息。这么做的好处
在于,一旦从网站上提取到了数据,就可以随心所欲地处理它,比如创建一个温度表。可以创建一个每天运行的 cron 任务来跟踪当天的温度。

lynx 是一个非常值得深入研究的工具,详细信息访问其官方主页:

http://lynx.invisible-island.net/lynx.html

NOTE:
    -------------------------------------------------------------------------------------------------------------------------------------
    互联网无时不刻不在发生变化。如果花费了几个小时找到了 Web 页面上数据的精确位置,而几个星期后却发现数据已经不在了,脚本也没法工作了,
    不必感到惊讶。重要的是要知道从 Web 页面提取数据的过程。这样就可以将原理运用到任何情形中。

2.3 使用电子邮件
-----------------------------------------------------------------------------------------------------------------------------------------    
可用来从 shell 脚本中发送电子邮件的主要工具是 Mailx 程序。不仅可以用它交互地读取和发送消息,还可以用命令行参数指定如何发送消息。
系统上的 mail 命令实际上是 mailx 的符号链接:

[devalone@devalone 25]$ which mail
    /usr/bin/mail
    [devalone@devalone 25]$ ll /usr/bin/mail
    lrwxrwxrwx. 1 root root 5 2月   4 2016 /usr/bin/mail -> mailx

Mailx 程序发送消息的命令行的格式为:

mail [-eIinv] [-a header] [-b addr] [-c addr] [-s subj] to-addr

Mailx 命令行参数
    +-------+-----------------------------------------------------------------------------
    | 参 数    | 描 述
    +-------+-----------------------------------------------------------------------------
    | -a    | 指定额外的SMTP头部行
    +-------+-----------------------------------------------------------------------------
    | -b    | 给消息增加一个BCC:收件人
    +-------+-----------------------------------------------------------------------------
    | -c    | 给消息增加一个CC:收件人
    +-------+-----------------------------------------------------------------------------
    | -e    | 如果消息为空,不要发送消息
    +-------+-----------------------------------------------------------------------------
    | -i    | 忽略TTY中断信号
    +-------+-----------------------------------------------------------------------------
    | -I    | 强制Mailx以交互模式运行
    +-------+-----------------------------------------------------------------------------
    | -n    | 不要读取/etc/mail.rc启动文件
    +-------+-----------------------------------------------------------------------------
    | -s    | 指定一个主题行
    +-------+-----------------------------------------------------------------------------
    | -v    | 在终端上显示投递细节
    +-------+-----------------------------------------------------------------------------

完全可以使用命令行参数来创建整个电子邮件消息。唯一需要添加的就是消息正文。

需要将文本重定向给 mail命令。下面这个简单的例子演示了如何直接在命令行上创建和发送电子邮件消息:

[devalone@devalone 25]$ echo "This is a test message" | mailx -s "Test message" devalone

Mailx 程序将来自 echo 命令的文本作为消息正文发送。这提供了一个从 shell 脚本发送消息的简单途径。

[devalone@devalone 25]$ cat factmail.sh
    #!/bin/bash
    # mailing the answer to a factorial

MAIL=$(which mailx)

factorial=1
    counter=1

read -p "Enter the number: " value
    while [ $counter -le $value ]
    do
            factorial=$[$factorial * $counter]
            counter=$[$counter + 1]
    done

echo The factorial of $value is $factorial | $MAIL -s "Factorial answer" $USER
    echo "The result has been mailed to you."

这段脚本不会假定 Mailx 程序位于标准位置。它使用 which 命令来确定 mail程序在哪里。

在计算出阶乘函数的结果后,shell 脚本使用 mail 命令将这个消息发送到用户自定义的 $USER 环境变量,这应该是运行这个脚本的人。

运行:
    [devalone@devalone 25]$ ./factmail.sh
    Enter the number: 5
    The result has been mailed to you.

在消息正文中只发送一行文本有时会不方便。通常,需要将整个输出作为电子邮件消息发送。这种情况总是可以将文本重定向到临时文件中,然后用 cat
命令将输出重定向给 mail程序。

diskmail 程序用 date命令(采用了特殊格式)得到了当前日期,找到 Mailx程序的位置后创建了一个临时文件。接着用 df 命令显示了当前磁盘空间的
统计信息,并将输出重定向到了那个临时文件。

然后使用第一个命令行参数作为目的地地址,使用当前日期作为邮件主题,将临时文件重定向到 mail命令。在运行这个脚本时,不会看到任何命令行输出。

[devalone@devalone 25]$ ./diskmail.sh devalone

可以通过 mail 命令查看当前用户的邮件,非本文关注内容,此处不做演示。

系列目录:

Linux shell 脚本编程-实战篇(一)

Linux shell 脚本编程-实战篇(二)

Linux shell 脚本编程-实战篇(三)

-----------------------------------------------------------------------------------------------------------------------------------------
参考:

《Linux 命令行与 shell 脚本编程大全》 第 3 版 —— 2016.8(美)Richard Blum  Cristine Bresnahan

Linux shell 脚本编程-实战篇(二)相关推荐

  1. Linux shell 脚本编程-实战篇(三)

    继: Linux shell 脚本编程-实战篇(二) 3. 一些小有意思的脚本 3.1 发送消息 3.1.1 功能分析 对于这种简单的脚本,需要的功能不多.涉及的一些命令很常见,下面了解脚本所需的几个 ...

  2. Linux shell脚本编程(二)

    Linux shell脚本编程(二) -------------------------------------------------------------------- 注:如果你对python ...

  3. Linux shell脚本编程(三)

    Linux shell脚本编程 -------------------------------------------------------------------- 注:如果你对python感兴趣 ...

  4. Linux shell脚本编程(一)

    -------------------------------------------------------------------- 注:如果你对python感兴趣,我这有个学习Python基地, ...

  5. Linux Shell脚本编程基础

    2 Linux Shell脚本编程基础 发表于: Linux, Shell, UNIX, 资源分享 | 作者: 谋万世全局者 标签: Linux,Shell,编程基础,脚本 本文作者:Leal 授权许 ...

  6. linux shell 脚本编程基本语法

    linux shell脚本编程基本语法 Shell script是利用shell的功能所写的一个"程序",这个程序是使用纯文本文件,将一些Linux Shell的语法与命令(含外部 ...

  7. 【shell笔记】Linux Shell脚本编程入门知识点全面涵盖

    本文是我对白树明老师shell课程笔记的总结,课程链接:https://www.bilibili.com/video/BV1j541157Sr?from=search&seid=9757674 ...

  8. LINUX——shell脚本编程

    一.什么是shell脚本编程 shell脚本并不是真正的编程语言,实际上就是命令的集合,类似于windows的批处理文件 二.编写shell脚本(文件格式为.sh) 1.编写一个helowrold+日 ...

  9. shell脚本编程笔记(二)—— 执行数学运算

    数学运算在编程中也很重要,shell对它的支持并不算好,本文整理一下shell进行数学运算的途径,各种方法的缺点. 一. expr命令 shell最开始处理数学表达式的命令,可以在命令行做算术运算,参 ...

最新文章

  1. 你还在用GDB调试程序吗?
  2. 华为手机文件夹android,安卓手机文件目录详解
  3. ValueError: Program neato not found in path.
  4. cogs 610. 数对的个数
  5. git stash 强制恢复_开发中必须要掌握的 Git 技巧
  6. Boost:基于Boost的一个微小的actor框架
  7. 零基础学Python(第三章 基础语法)
  8. Kubernetes的Device Plugin机制源码解析
  9. 博图程序需要手动同步_贴吧求助帖博图实例单按钮控制灯的程序
  10. codeforces82 D. Two out of Three(记忆化搜索)
  11. HTML设置单边圆角,如何在html中做圆角矩形和 只有右边的分隔线
  12. 高性能 socket 框架
  13. Win10之fastboot devices无反应
  14. 在ubuntu下安装MonoDevelop
  15. Android 3.0“.NET研究”七大特性全解析
  16. 李航——《统计学习方法》(一)
  17. 管理信息系统可行性分析报告_软考复习笔记|项目管理过程与可行性分析及可行性分析报告编写...
  18. 图解Java类加载机制
  19. SVG排版教程 | SVG排版入门基础知识汇总
  20. html特殊符号小企鹅,企鹅侦探名字如何取特殊 名字可以使用的特殊符号

热门文章

  1. 常用计算机的外部接口,笔记本电脑常见的外部接口及作用介绍
  2. 算法工程师过去这一年:理想很丰满,现实很骨感
  3. XP下VS2005导入excel类
  4. 阿里旺旺(不是掏宝旺旺)
  5. ObjectARX 类库
  6. javascript制作万年历
  7. 总结三:确定如何招聘合适的程序员
  8. 大数据 通用 调度系统 的设计和实现
  9. 微信小程序遇到的坑系列---小程序上传图片线上失败
  10. 做外贸怎么收款?2020最新外贸B2B收款结汇方法详解!