2.1 调用脚本
在最简单的情况下,脚本只不过是一组系统命令的集合,存储在一个文件中。至少,这样可以避免每次调用时都要重新输入那一串命令。
示例 2-1:cleanup:清理 /var/log 下日志文件的脚本
# Cleanup
# 当然要以 root 身份运行。
cd /var/log
cat /dev/null > messages
cat /dev/null > wtmp
echo "Log files cleaned up."
这里没有什么特别的,只是一组可以在控制台或终端窗口中逐条输入的命令。将命令放入脚本的好处远不止于此——脚本变成了一个“程序”,一个“工具”,而且可以很容易地根据具体应用进行修改或定制。
示例 2-2:cleanup:改进版清理脚本
#!/bin/bash
# Proper header for a Bash script.
# Cleanup, version 2
# 当然要以 root 身份运行。
# 插入代码以在非 root 时打印错误信息并退出。
LOG_DIR=/var/log
# 变量比硬编码值更好。
cd $LOG_DIR
cat /dev/null > messages
cat /dev/null > wtmp
echo "Logs cleaned up."
exit
# 用 exit 正确地退出脚本。
# 不带参数的 exit 返回前一条命令的退出状态。
现在,这已经开始像一个真正的脚本了。但我们还可以做得更好……
示例 2-3:cleanup:增强和通用版脚本
#!/bin/bash
# Cleanup, version 3
# 警告:
# -------
# 这个脚本用到了许多后面会讲到的特性。
# 当你学完本书前半部分时,这些都不再神秘。
LOG_DIR=/var/log
ROOT_UID=0 # 只有 UID 为 0 的用户有 root 权限。
LINES=50 # 默认保留的行数。
E_XCD=86 # 不能切换目录?
E_NOTROOT=87 # 非 root 退出错误。
# 当然要以 root 身份运行。
if [ "$UID" -ne "$ROOT_UID" ]
then
echo "Must be root to run this script."
exit $E_NOTROOT
fi
if [ -n "$1" ] # 检查命令行参数是否存在(非空)。
then
lines=$1
else
lines=$LINES # 默认值
fi
cd $LOG_DIR
if [ `pwd` != "$LOG_DIR" ] # 或 if [ "$PWD" != "$LOG_DIR" ]
then
echo "Can't change to $LOG_DIR."
exit $E_XCD
fi
tail -n $lines messages > mesg.temp # 保留日志文件最后部分
mv mesg.temp messages # 重命名为系统日志文件
cat /dev/null > wtmp
echo "Log files cleaned up."
exit 0
# 脚本退出时返回 0 表示成功
由于你可能不希望清空整个系统日志,这个版本的脚本会保留日志文件的最后一部分。你会不断发现优化脚本以提高效率的方法。
Sha-Bang(#!)说明
sha-bang(#!)在脚本开头告诉系统,这个文件是一组要交给指定命令解释器执行的命令。#! 实际上是一个两字节的“魔数”,标记文件类型,这里表示可执行的 shell 脚本。紧跟在 #! 后面的是一个路径名,指向解释脚本命令的程序(如 shell、编程语言或工具)。该解释器会从脚本顶部(#! 后一行)开始执行命令,忽略注释。
常见的 sha-bang 行有:
#!/bin/sh
#!/bin/bash
#!/usr/bin/perl
#!/usr/bin/tcl
#!/bin/sed -f
#!/bin/awk -f
每一行都调用不同的命令解释器,比如 /bin/sh(大多数 Linux 系统默认是 bash)等。使用 #!/bin/sh
可以让脚本在非 Linux 的 UNIX 系统上也能运行,但会失去 bash 的特有功能。该脚本会遵循 POSIX sh 标准。
注意,sha-bang 行中的路径必须正确,否则运行脚本时只会看到“Command not found.”的错误信息。
如果脚本只包含通用的系统命令,没有用到 shell 的内部指令,可以省略 #!。但如果脚本中有变量赋值等 shell 特性,必须加上 #!。
小贴士
本教程鼓励以模块化方式构建脚本。请收集和整理有用的“模板”代码片段,将来会积累出丰富的脚本库。例如,下面的脚本开头用于检测参数数量是否正确:
E_WRONG_ARGS=85
script_parameters="-a -h -m -z"
if [ $# -ne $Number_of_expected_args ]
then
echo "Usage: `basename $0` $script_parameters"
exit $E_WRONG_ARGS
fi