61、实用脚本创作与有趣小脚本开发

实用脚本创作与有趣小脚本开发

1. 高级脚本功能概述

在编写 shell 脚本时,有一些高级功能可以帮助我们实现更多复杂的任务。下面将介绍三个重要的高级功能:使用 MySQL 服务器存储数据、使用 lynx 浏览器提取网页数据以及使用 Mailx 程序发送报告。

  • 使用 MySQL 服务器存储数据

    • 首先,为应用程序在 MySQL 中创建一个数据库和唯一的用户账户,并仅授予该用户账户对该数据库的权限。
    • 然后,创建表来存储应用程序使用的数据。
    • 最后,使用 mysql 命令行工具与 MySQL 服务器进行交互,提交 SELECT 查询并检索结果进行显示。
  • 使用 lynx 浏览器提取网页数据

    • lynx 是一个基于文本的浏览器,可以将网页上的所有文本转储出来。
    • 利用标准的 shell 编程技能来存储这些数据,并搜索所需的内容。
  • 使用 Mailx 程序发送报告

    • Mailx 程序允许我们使用 Linux 系统上安装的电子邮件服务器轻松地将命令输出发送到任何电子邮件地址。
2. 有趣小脚本:发送消息

学习编写 bash shell 脚本的主要目的是创建自己的 Linux 系统实用工具。不过,有时候编写一些有趣的脚本也有助于巩固脚本编写的概念。下面将详细介绍一个用于在 Linux 系统上向其他用户发送消息的脚本。

2.1 所需功能理解

这个简单的脚本只需要几个功能,部分命令是常见的,而有些可能不太熟悉。下面将介绍所需的命令。

  • 确定系统上的用户
    使用 who 命令可以查看当前登录到系统的所有用户。示例如下:
    bash $ who christine tty2 2015-09-10 11:43 timothy tty3 2015-09-10 11:46 [...] $
    默认情况下, who 命令提供简短的信息,与 who -s 命令输出相同,包含以下内容:

    • 用户姓名
    • 用户的终端
    • 用户登录系统的时间

    发送消息时,只需要前两项信息,即用户名和用户当前的终端。

  • 允许消息接收
    用户可以使用 mesg 实用程序禁止任何人向他们发送消息。因此,在尝试发送消息之前,最好检查消息是否被允许。

    • 检查自己的消息状态:
      bash $ mesg is n $
      结果 is n 表示消息功能已关闭,如果结果为 is y ,则表示允许接收消息。
    • 不同 Linux 发行版的默认设置不同,例如 Ubuntu 默认关闭消息功能,而 CentOS 默认开启。
    • 检查其他用户的消息状态:
      bash $ who -T christine - tty2 2015-09-10 12:56 timothy - tty3 2015-09-10 11:46 [...] $
      用户名后面的短横线 - 表示该用户关闭了消息功能,加号 + 表示允许接收消息。
    • 开启自己的消息接收功能:
      bash $ whoami christine $ $ mesg y $ $ mesg is y $
      通过执行 mesg y 命令,用户 christine 开启了消息接收功能。
  • 向其他用户发送消息
    该脚本的主要工具是 write 命令。只要消息功能被允许, write 命令就可以使用用户名和当前终端向另一个登录用户发送消息。需要注意的是, write 命令只能向虚拟控制台终端登录的用户成功发送消息,登录到图形环境的用户无法接收消息。

    示例:从用户 christine 向登录在 tty3 终端的用户 timothy 发送消息:
    bash $ who christine tty2 2015-09-10 13:54 timothy tty3 2015-09-10 11:46 [...] $ $ write timothy tty3 Hello Tim! $
    执行 write 命令后,会出现一个空行,用于输入消息文本。可以输入多行消息,按 Enter 键换行,输入完成后按 Ctrl+D 组合键发送整个消息。

    接收者看到的消息如下:
    Message from christine@server01 on tty2 at 14:11 ... Hello Tim! EOF
    接收者可以看到发送消息的用户和终端,以及时间戳。消息底部的 EOF 表示文件结束,让接收者知道整个消息已显示完毕。通常,接收者收到消息后需要按 Enter 键才能再次显示提示符。

3. 创建脚本

使用脚本发送消息可以克服一些潜在的问题,例如在系统中有大量用户时,查找要发送消息的用户会很麻烦,并且需要确定该用户是否允许接收消息。脚本可以加快这个过程,让我们轻松地向特定用户发送消息。

3.1 检查用户是否登录

通过在脚本执行时传递一个参数来指定要发送消息的用户。使用以下脚本代码来确定该用户是否登录:

# Determine if user is logged on:
#
logged_on=$(who | grep -i -m 1 $1 | gawk '{print $1}')
#
if [ -z $logged_on ]
then
   echo "$1 is not logged on."
   echo "Exiting script..."
   exit
fi
#

在上述代码中, who 命令的结果通过管道传递给 grep 命令, grep 命令使用 -i 选项忽略大小写, -m 1 选项确保只匹配第一个结果。如果用户未登录, grep 命令将不产生输出;如果用户登录,将输出用户名的第一个登录信息。这个输出再传递给 gawk 命令, gawk 命令只返回第一个项目,即用户名或空字符串。最终结果存储在 logged_on 变量中。

如果 logged_on 变量为空字符串,表示用户未登录,脚本将输出相应信息并退出;如果用户登录,脚本将继续执行。

示例:传递用户名 Charlie 作为参数,该用户当前未登录:

$ ./mu.sh Charlie
Charlie is not logged on.
Exiting script...
$
3.2 检查用户是否允许接收消息

使用以下脚本代码来确定登录用户是否允许接收消息:

# Determine if user allows messaging:
#
allowed=$(who -T | grep -i -m 1 $1 | gawk '{print $2}')
#
if [ $allowed != "+" ]
then
   echo "$1 does not allowing messaging."
   echo "Exiting script..."
   exit
fi
#

这里使用 who -T 命令和选项来显示用户的消息状态。结果通过管道传递给 grep gawk 命令,提取消息指示符并存储在 allowed 变量中。如果 allowed 变量的值不是 + ,表示用户不允许接收消息,脚本将输出相应信息并退出;否则,脚本将继续执行。

示例:用户 Samantha 当前已登录但关闭了消息功能:

$ ./mu.sh Samantha
Samantha does not allowing messaging.
Exiting script...
$
3.3 检查是否包含消息

消息作为脚本的第二个参数传递,因此需要检查是否包含消息参数。使用以下脚本代码:

# Determine if a message was included:
#
if [ -z $2 ]
then
    echo "No message parameter included."
    echo "Exiting script..."
    exit
fi
#

如果第二个参数为空字符串,表示没有包含消息,脚本将输出相应信息并退出。

示例:传递用户名 Timothy 但未包含消息:

$ ./mu.sh Timothy
No message parameter included.
Exiting script...
$
3.4 发送简单消息

在发送消息之前,需要确定用户的当前终端并存储在变量中。使用以下脚本代码:

# Send message to user:
#
uterminal=$(who | grep -i -m 1 $1 | gawk '{print $2}')
#
echo $2 | write $logged_on $uterminal
#

who grep gawk 命令再次用于确定用户的当前终端,并存储在 uterminal 变量中。使用 echo 命令将消息发送到标准输出,然后通过管道传递给 write 命令, logged_on 变量保存用户名, uterminal 变量保存用户的当前终端。

示例:向用户 Timothy 发送简单消息 test

$ ./mu.sh Timothy test
$

用户 Timothy 在其终端上收到的消息如下:

Message from christine@server01 on tty2 at 10:23 ...
test
EOF
3.5 发送长消息

当需要发送包含多个单词的长消息时,原脚本会出现问题,因为 bash shell 将空格视为参数分隔符。可以使用 shift 命令和 while 循环来解决这个问题。

# Determine if there is more to the message:
#
shift
#
while [ -n "$1" ]
do
   whole_message=$whole_message' '$1
   shift
done
#

shift 命令允许我们处理脚本参数,将下一个参数移动到 $1 位置。在 while 循环中,不断将每个消息单词添加到 whole_message 变量中,直到处理完所有参数。

修改脚本以发送 whole_message 变量:

# Send message to user:
#
uterminal=$(who | grep -i -m 1 $1 | gawk '{print $2}')
#
echo $whole_message | write $logged_on $uterminal
#

但是,使用 shift 命令会移除 $1 参数的内容,导致脚本在使用 $1 时产生错误。可以使用一个变量 muser 来保存 $1 参数的值:

# Save the username parameter
#
muser=$1
#

然后将脚本中所有的 $1 替换为 muser

# Determine if user is logged on:
#
logged_on=$(who | grep -i -m 1 $muser | gawk '{print $1}')
#
if [ -z $logged_on ]
then
   echo "$muser is not logged on."
   echo "Exiting script..."
   exit
fi
#
# Determine if user allows messaging:
#
allowed=$(who -T | grep -i -m 1 $muser | gawk '{print $2}')
#
if [ $allowed != "+" ]
then
   echo "$muser does not allowing messaging."
   echo "Exiting script..."
   exit
fi
#
# Determine if a message was included:
#
if [ -z $2 ]
then
    echo "No message parameter included."
    echo "Exiting script..."
    exit
fi
#
# Determine if there is more to the message:
#
shift
#
while [ -n "$1" ]
do
   whole_message=$whole_message' '$1
   shift
done
#
# Send message to user:
#
uterminal=$(who | grep -i -m 1 $muser | gawk '{print $2}')
#
echo $whole_message | write $logged_on $uterminal
#
exit

示例:向用户 Timothy 发送长消息 The boss is coming! Look busy!

$ ./mu.sh Timothy The boss is coming! Look busy!
$

用户 Timothy 在其终端上收到的消息如下:

Message from christine@server01 on tty2 at 10:30 ...
The boss is coming! Look busy!
EOF
4. 脚本改进建议

以下是一些可以尝试的脚本改进建议:
- 不将用户名和消息作为参数传递,而是使用选项。
- 如果用户登录到多个终端,允许向这些多个终端发送消息。(提示:使用多个 write 命令。)
- 如果要发送的消息是给当前仅登录到 GUI 的用户,向脚本用户输出消息并退出脚本。(记住 write 命令只能向虚拟控制台终端写入消息。)
- 允许将存储在文件中的长消息发送到终端。(提示:使用 cat 命令的输出通过管道传递给 write 实用程序,而不是 echo 命令。)

下面是整个消息脚本的流程图:

graph TD;
    A[开始] --> B[检查用户是否登录];
    B -- 用户未登录 --> C[输出提示信息并退出];
    B -- 用户已登录 --> D[检查用户是否允许接收消息];
    D -- 用户不允许 --> E[输出提示信息并退出];
    D -- 用户允许 --> F[检查是否包含消息];
    F -- 未包含消息 --> G[输出提示信息并退出];
    F -- 包含消息 --> H[处理长消息];
    H --> I[确定用户终端];
    I --> J[发送消息];
    J --> K[结束];

通过以上步骤,我们可以创建一个简单而有趣的脚本,用于在 Linux 系统上向其他用户发送消息。同时,还可以根据自己的需求对脚本进行改进和扩展。

实用脚本创作与有趣小脚本开发

5. 操作步骤总结

为了更清晰地展示创建发送消息脚本的过程,下面将整个流程总结为详细的操作步骤:
1. 确定系统上的用户 :使用 who 命令查看当前登录系统的所有用户,获取用户名和终端信息。
2. 检查消息接收权限 :使用 mesg 命令检查自己的消息接收状态,使用 who -T 命令检查其他用户的消息接收状态。若要开启消息接收,使用 mesg y 命令。
3. 测试发送消息 :使用 write 命令向已登录且允许接收消息的用户发送消息,按 Ctrl+D 组合键完成消息发送。
4. 创建脚本
- 检查用户是否登录 :使用 who | grep -i -m 1 $1 | gawk '{print $1}' 确定用户是否登录。
- 检查用户是否允许接收消息 :使用 who -T | grep -i -m 1 $1 | gawk '{print $2}' 检查用户消息接收权限。
- 检查是否包含消息 :检查第二个参数是否为空。
- 发送简单消息 :确定用户当前终端,使用 echo $2 | write $logged_on $uterminal 发送消息。
- 处理长消息 :使用 shift 命令和 while 循环处理长消息,将消息存储在 whole_message 变量中。
- 修正脚本错误 :使用 muser 变量保存用户名,替换脚本中的 $1

6. 代码示例总结

下面将创建消息发送脚本的完整代码示例再次给出,方便参考:

#!/bin/bash
#
#mu.sh - Send a Message to a particular user
#############################################
#
# Save the username parameter
#
muser=$1
#
# Determine if user is logged on:
#
logged_on=$(who | grep -i -m 1 $muser | gawk '{print $1}')
#
if [ -z $logged_on ]
then
   echo "$muser is not logged on."
   echo "Exiting script..."
   exit
fi
#
# Determine if user allows messaging:
#
allowed=$(who -T | grep -i -m 1 $muser | gawk '{print $2}')
#
if [ $allowed != "+" ]
then
   echo "$muser does not allowing messaging."
   echo "Exiting script..."
   exit
fi
#
# Determine if a message was included:
#
if [ -z $2 ]
then
    echo "No message parameter included."
    echo "Exiting script..."
    exit
fi
#
# Determine if there is more to the message:
#
shift
#
while [ -n "$1" ]
do
   whole_message=$whole_message' '$1
   shift
done
#
# Send message to user:
#
uterminal=$(who | grep -i -m 1 $muser | gawk '{print $2}')
#
echo $whole_message | write $logged_on $uterminal
#
exit
7. 脚本改进详细分析
7.1 使用选项替代参数

目前脚本是通过参数传递用户名和消息,可使用选项来提高脚本的灵活性。例如,使用 -u 选项指定用户名, -m 选项指定消息。以下是修改后的示例代码:

#!/bin/bash
#
#mu.sh - Send a Message to a particular user
#############################################
while getopts "u:m:" opt; do
  case $opt in
    u)
      muser=$OPTARG
      ;;
    m)
      message=$OPTARG
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1
      ;;
    :)
      echo "Option -$OPTARG requires an argument." >&2
      exit 1
      ;;
  esac
done

# Determine if user is logged on:
#
logged_on=$(who | grep -i -m 1 $muser | gawk '{print $1}')
#
if [ -z $logged_on ]
then
   echo "$muser is not logged on."
   echo "Exiting script..."
   exit
fi
#
# Determine if user allows messaging:
#
allowed=$(who -T | grep -i -m 1 $muser | gawk '{print $2}')
#
if [ $allowed != "+" ]
then
   echo "$muser does not allowing messaging."
   echo "Exiting script..."
   exit
fi
#
# Determine if a message was included:
#
if [ -z "$message" ]
then
    echo "No message parameter included."
    echo "Exiting script..."
    exit
fi
#
# Determine if there is more to the message:
#
whole_message=$message
#
# Send message to user:
#
uterminal=$(who | grep -i -m 1 $muser | gawk '{print $2}')
#
echo $whole_message | write $logged_on $uterminal
#
exit
7.2 向多个终端发送消息

如果用户登录到多个终端,可使用循环遍历所有终端并发送消息。以下是修改后的代码示例:

#!/bin/bash
#
#mu.sh - Send a Message to a particular user
#############################################
#
# Save the username parameter
#
muser=$1
#
# Determine if user is logged on:
#
logged_on=$(who | grep -i -m 1 $muser | gawk '{print $1}')
#
if [ -z $logged_on ]
then
   echo "$muser is not logged on."
   echo "Exiting script..."
   exit
fi
#
# Determine if user allows messaging:
#
allowed=$(who -T | grep -i -m 1 $muser | gawk '{print $2}')
#
if [ $allowed != "+" ]
then
   echo "$muser does not allowing messaging."
   echo "Exiting script..."
   exit
fi
#
# Determine if a message was included:
#
if [ -z $2 ]
then
    echo "No message parameter included."
    echo "Exiting script..."
    exit
fi
#
# Determine if there is more to the message:
#
shift
#
while [ -n "$1" ]
do
   whole_message=$whole_message' '$1
   shift
done
#
# Get all terminals of the user
#
terminals=$(who | grep -i $muser | gawk '{print $2}')
#
for terminal in $terminals; do
    echo $whole_message | write $logged_on $terminal
done
#
exit
7.3 处理仅登录 GUI 的用户

若要判断用户是否仅登录到 GUI,可以通过检查 who 命令的输出是否不包含虚拟控制台终端信息。以下是修改后的代码示例:

#!/bin/bash
#
#mu.sh - Send a Message to a particular user
#############################################
#
# Save the username parameter
#
muser=$1
#
# Determine if user is logged on:
#
logged_on=$(who | grep -i -m 1 $muser | gawk '{print $1}')
#
if [ -z $logged_on ]
then
   echo "$muser is not logged on."
   echo "Exiting script..."
   exit
fi
#
# Check if user is only logged in GUI
#
if ! who | grep -i $muser | grep -q tty; then
    echo "$muser is only logged in GUI. Cannot send message."
    echo "Exiting script..."
    exit
fi
#
# Determine if user allows messaging:
#
allowed=$(who -T | grep -i -m 1 $muser | gawk '{print $2}')
#
if [ $allowed != "+" ]
then
   echo "$muser does not allowing messaging."
   echo "Exiting script..."
   exit
fi
#
# Determine if a message was included:
#
if [ -z $2 ]
then
    echo "No message parameter included."
    echo "Exiting script..."
    exit
fi
#
# Determine if there is more to the message:
#
shift
#
while [ -n "$1" ]
do
   whole_message=$whole_message' '$1
   shift
done
#
# Send message to user:
#
uterminal=$(who | grep -i -m 1 $muser | gawk '{print $2}')
#
echo $whole_message | write $logged_on $uterminal
#
exit
7.4 发送文件中的长消息

若要发送存储在文件中的长消息,可以使用 cat 命令读取文件内容并通过管道传递给 write 命令。以下是修改后的代码示例:

#!/bin/bash
#
#mu.sh - Send a Message to a particular user
#############################################
#
# Save the username parameter
#
muser=$1
#
# Determine if user is logged on:
#
logged_on=$(who | grep -i -m 1 $muser | gawk '{print $1}')
#
if [ -z $logged_on ]
then
   echo "$muser is not logged on."
   echo "Exiting script..."
   exit
fi
#
# Determine if user allows messaging:
#
allowed=$(who -T | grep -i -m 1 $muser | gawk '{print $2}')
#
if [ $allowed != "+" ]
then
   echo "$muser does not allowing messaging."
   echo "Exiting script..."
   exit
fi
#
# Determine if a file was included:
#
if [ -z $2 ]
then
    echo "No file parameter included."
    echo "Exiting script..."
    exit
fi
#
if [ ! -f $2 ]
then
    echo "File $2 does not exist."
    echo "Exiting script..."
    exit
fi
#
# Send message to user:
#
uterminal=$(who | grep -i -m 1 $muser | gawk '{print $2}')
#
cat $2 | write $logged_on $uterminal
#
exit
7. 总结

通过以上内容,我们学习了如何使用高级功能创建实用的 shell 脚本,包括使用 MySQL 服务器存储数据、使用 lynx 浏览器提取网页数据以及使用 Mailx 程序发送报告。同时,详细介绍了创建一个有趣的消息发送脚本的过程,包括确定系统用户、检查消息接收权限、测试发送消息、创建脚本以及对脚本进行改进。

在创建脚本的过程中,我们使用了多种命令和技巧,如 who mesg write grep gawk shift while 循环等。通过不断改进脚本,我们可以使其更加灵活和强大,满足不同的需求。

希望这些内容能帮助你更好地掌握 shell 脚本的编写,让你在 Linux 系统中更加高效地完成各种任务。

下面是脚本改进功能的总结表格:
| 改进功能 | 实现方法 |
| — | — |
| 使用选项替代参数 | 使用 getopts 命令解析选项 |
| 向多个终端发送消息 | 遍历用户的所有终端,使用 write 命令发送消息 |
| 处理仅登录 GUI 的用户 | 检查 who 命令输出是否包含虚拟控制台终端信息 |
| 发送文件中的长消息 | 使用 cat 命令读取文件内容并通过管道传递给 write 命令 |

以下是脚本改进流程的 mermaid 流程图:

graph TD;
    A[开始] --> B[选择改进功能];
    B -- 使用选项替代参数 --> C[使用getopts解析选项];
    C --> D[修改脚本逻辑];
    B -- 向多个终端发送消息 --> E[遍历用户终端];
    E --> F[使用write发送消息];
    B -- 处理仅登录GUI的用户 --> G[检查终端信息];
    G -- 仅登录GUI --> H[输出提示并退出];
    G -- 非仅登录GUI --> I[继续执行脚本];
    B -- 发送文件中的长消息 --> J[检查文件是否存在];
    J -- 文件存在 --> K[使用cat读取文件内容];
    K --> L[使用write发送消息];
    J -- 文件不存在 --> M[输出提示并退出];
    D --> N[结束];
    F --> N[结束];
    I --> N[结束];
    L --> N[结束];
    H --> N[结束];
    M --> N[结束];
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值