背景:
分组自研的数据库审计平台已在windows环境下,实现了一键拉取Oracle数据库性能报告的功能。
最近接到审计平台开发的小任务:将windows环境下实现一键拉取oracle数据库性能报告的bat脚本改为linux下的
shell脚本。
脚本改写的很快,三百多行的bat脚本,半天就改写成了shell,接下来就是最痛苦的测试环节了。

踩坑开始:
bat脚本在定义变量时,将连接数据库的密码定义为名为PWD的变量(如下),踩坑由此开始。。。

@echo off
...
set PWD=xxx
...

我在定义连接oracle的用户密码时,便参照bat脚本,仍使用PWD作为密码变量:

#################setting variables######################
。
。
TNS=dbname
PWD=pass1234
。
。
#################Making gather&scan Files######################
。
。
sqlplus dbaudit/$PWD@$TNS <<EOF >>sqlplus.log          --第1部分
here is command1!
EOF
。
。
#################Spooling Reports######################
cd $SHELL_PATH/$1
echo -e "Spooling Reports..."
for(( i = 0; i < 10; i++ ))  
do  
{                              
    sqlplus dbaudit/$PWD@$TNS <<EOF >>sqlplus.log      --第2部分
    here is command2!
    EOF
}&  
done  
wait 
。
。

为了拉取oracle报告,在脚本中有多次连接数据库的操作:

sqlplus username/$PWD@$TNS <<EOF >>sqlplus.log
...
EOF

脚本看起来毫无破绽,可是执行时第1部分的sqlplus命令时,可以成功连接数据库,并执行相关操作;而执行到脚本第2部分的sqlplus命令时,却总是报sqlplus的语法错误!
这是为何呢?!
思来想去无果,百度是不可能有结果了,因为报错很直白,就是sqlplus语法不对。

Spooling Reports...

SQL*Plus: Release 11.2.0.1.0 Production on Thu May 17 12:28:13 2018

Copyright (c) 1982, 2009, Oracle.  All rights reserved.

SQL*Plus: Release 11.2.0.1.0 Production

Copyright (c) 1982, 2009, Oracle.  All rights reserved.

Use SQL*Plus to execute SQL, PL/SQL and SQL*Plus statements.

Usage 1: sqlplus -H | -V

    -H             Displays the SQL*Plus version and the
                   usage help.
    -V             Displays the SQL*Plus version.

Usage 2: sqlplus [ [<option>] [{logon | /nolog}] [<start>] ]

于是,将变量部分和报错部分的脚本提取出,写在test.sh中单独执行,邪门的事情发生了,执行过程很成功!
奇怪了,脚本前后同样的命令,前面的成功,后面的失败了,why?!
仔细阅读脚本,中间只有一次“cd $SHELL_PATH/$1”的命令,难道是这个命令导致的?不应该呀!

继续将报错脚本拿出来单独执行,一次偶然的"echo $PWD"揭示了真相!

[padba@cnsz081003 ~]$ echo $PWD
/paic/dba/tmp/padba

纳尼!PWD居然是linux系统自带的变量,而且显示的就是当前目录!

于是推断,在执行“cd $SHELL_PATH/$1”这样的change directory命令后,系统的PWD变量覆盖了脚本开始时
定义的PWD=pass1234,也就是说,在切换目录后,PWD的值就不是"pass1234"了,而是一个目录,也就是"$SHELL_PATH/$1"对应的值!

验证推断:

[padba@cnsz081003 ~]$ export PWD=pass1234   --手动定义PWD变量
[padba@cnsz081003 pass1234]$ echo $PWD
pass1234                                    --显示PWD变量值为pass1234,没毛病!
[padba@cnsz081003 pass1234]$ cd             --切换目录
[padba@cnsz081003 ~]$ echo $PWD
/paic/dba/tmp/padba                         --PWD的值变为当前目录!

至此,真相大白!
修改脚本中的PWD为PASSWD后,报错消失,脚本顺利完成拉取报告的使命!

总结:
linux中有许多类似$PWD这类的变量,我们在脚本中定义变量名时,要避开系统自带的变量名,否则会导致灰常奇怪且让人欲罢不能的ERROR!