第2章 Sha-Bang(#!)起步

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
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容