加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 黄冈站长网 (http://www.0713zz.com/)- 数据应用、建站、人体识别、智能机器人、语音技术!
当前位置: 首页 > 服务器 > 安全 > 正文

LinuxShell编程实战技巧

发布时间:2021-03-13 12:53:32 所属栏目:安全 来源:网络整理
导读:副标题#e# 目前,越来越多的企业应用会部署在 Linux 系统上的,而 Linux Shell 脚本可以极大地帮助我们完成这些应用的运维任务。这使得 Linux Shell 开发技能成为开发人员的一项重要的、有竞争力的技能。本文就笔者的实际开发经验,以 Korn Shell 为例分享
副标题[/!--empirenews.page--]

  目前,越来越多的企业应用会部署在 Linux 系统上的,而 Linux Shell 脚本可以极大地帮助我们完成这些应用的运维任务。这使得 Linux Shell 开发技能成为开发人员的一项重要的、有竞争力的技能。本文就笔者的实际开发经验,以 Korn Shell 为例分享了脚本开发中的常见问题及相关技巧。

LinuxShell编程实战技巧

 避免定时任务脚本的常见问题

  很多脚本在实际使用的时候往往是以定时任务的方式运行,而非手工运行。但是实现同样功能的脚本在这两种运行方式下可能遇到的问题不尽相同。

  以定时任务方式运行的脚本往往会遇到以下几个问题。

  • 路径问题:当前目录往往不是脚本文件所在目录。因此,脚本在引用其使用的外部文件,如配置文件和其它脚本文件时,无法方便得使用相对路径。
  • 命令找不到问题:脚本中使用到的一些外部命令,在手工执行脚本的时候可以正常调用。但是在定时任务下运行则可能出现脚本解析器找不到相关命令的问题。
  • 脚本重复运行问题:一次脚本的执行未结束,而下一次脚本的运行已经开始。导致系统中有多个进程在同时运行同一个脚本。

  下面分享定时任务脚本开发中上述几个常见问题的处理方法。

  路径问题

 定时任务下当前路径往往不是脚本文件所在目录。因此我们需要用绝对路径来引用。即先获取脚本所在目录,然后以该目录为基础采用绝对路径的方式去引用脚本所需的外部文件。方法如下面代码所示。

  清单 1. 获取脚本文件所在路径

#!/usr/bin/ksh

echo "Current path is: `pwd`"
scriptPath=`dirname $0` #获取脚本所在路径

echo "The script is located at: $scriptPath"
cat "$scriptPath/readme" #使用绝对路径引用外部文件

  将清单 1 中的脚本置于目录/opt/demo/scripts/auto-task 下,并在 cron 中添加该脚本。定时任务运行输出如下。

  Current path is: /home/viscent

  The script is located at: /opt/demo/scripts/auto-task

  命令找不到问题

  定时任务下运行的脚本可能出现脚本解析器找不到相关命令的问题。比如 Oracle 数据库中的 sqlplus 命令,脚本在调用该命令时若没有特殊处理则在定时任务下执行会使脚本解析器无法找到这个命令,出现如下所示的错误提示:

  sqlplus: command not found

  这是因为脚本在定时任务下执行时脚本是由非登录式 Shell 来执行的,并且执行脚本的父 Shell 并非 Oracle 用户的 Shell。因此,此时 Oracle 用户的.profile 文件并没有被调用。故解决的方法是在脚本的开头添加以下代码:

  清单 2. 解决找不到外部命令问题

source /home/oracle/.profile

  也就说,对于外部命令找不到的问题,可以通过在脚本的开头加一个 source 用户的.profile 文件的语句来解决。

  脚本重复运行问题

  定时任务脚本的另外一个常见问题是脚本重复运行的问题。比如,一个脚本被设置为每 5 分钟运行一次。若某一次该脚本的运行无法在 5 分钟内结束的话,定时任务服务仍然会新启一个进程来执行该脚本。这时就出现了运行同一个脚本的多个进程。而这可能导致脚本功能紊乱。并且浪费了系统资源。 避免脚本重复运行的方法通常有两种。一是在脚本执行时先检查系统是否存在运行该脚本的其它进程。若存在,则终止当前脚本的运行。二是,脚本运行时检查系统中是否存在其它进程运行该脚本。若存在,则结束那个进程(此方法有一定风险,慎用!)。这两种方法均需要在脚本的开头检查系统是否已经存在运行当前脚本的进程,若存在这样的进程则获取该进程的 PID。示例代码如下清单 3 所示。

  清单 3. 防止脚本重复运行方法 1

#!/usr/bin/ksh

main(){
selfPID="$$"
scriptFile="$0"

typeset existingPid
existingPid=`getExistingPIDs $selfPID "$scriptFile"`

if [ ! -z "$existingPid" ]; then
  echo "The script already running,exiting..."
  exit -1
fi

doItsTask

}

#获取除本身进程以外其它运行当前脚本的进程的 PID
getExistingPIDs(){
selfPID="$1"
scriptFile="$2"

ps -ef | grep "/usr/bin/ksh ${scriptFile}" | grep -v "grep" | awk "{ if($2!=$selfPID) print $2 }"
}

doItsTask(){
echo "Task is now being executed..."
sleep 20  #睡眠 20s,以模拟脚本在执行需要长时间完成的任务
}

main $*

  清单 4. 防止脚本重复运行方法 2

#!/usr/bin/ksh

main(){
selfPID="$$"
scriptFile="$0"

typeset existingPid
existingPid=`getExistingPIDs $selfPID "$scriptFile"`

if [ ! -z "$existingPid" ]; then
  echo "The script already running,killing it..."
  kill -9 "$existingPid" #此方法有一定风险,慎用!
fi

doItsTask

}

#获取除本身进程以外其它运行当前脚本的进程的 PID
getExistingPIDs(){
selfPID="$1"
scriptFile="$2"
ps -ef | grep "/usr/bin/ksh ${scriptFile}" | grep -v "grep" | awk "{ if($2!=$selfPID) print $2 }"
}

doItsTask(){
echo "Task is now being executed..."
sleep 20  #睡眠 20s,以模拟脚本在执行需要长时间完成的任务
}

main $*

 脚本调试技巧

  虽然 Shell 开发的一个普遍问题是调试困难,缺乏有效的调试工具。但是,我们可以采取一些能够一定程度上帮助我们规避调试困难的开发与调试的方式。 由于是脚本开发,不少人习惯于从直接地一行行地写代码,一个脚本里面甚至于一个函数都没有。虽然这种方式在语法上和功能上并无问题。但这增加了调试的难度。相反,如果采用模块化的方式去编写脚本,则使代码结构清晰、便于调试。这点,可以看这样一个例子。

(编辑:PHP编程网 - 黄冈站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读