Oracle中sqlplus登入報錯SP2-0667和SP2-0750探究

PiscesCanon發表於2017-06-14
前言:
朋友搭建11g兩節點的rac的時候,節點1能夠正常用sqlplus / as sysdba登入資料庫,但是節點2使用該命令報錯,如下:
  1. [oracle@oracle ~]$ sqlplus / as sysdba
  2. Error 6 initializing SQL*Plus
  3. SP2-0667: Message file sp1<lang>.msb not found
  4. SP2-0750: You may need to set ORACLE_HOME to your Oracle software directory

解決過程:

說明:由於是遠端解決,解決過程並沒有記錄,不過該問題很容易復現。
    後序會有另外一個復現該錯誤的方法,和此處遇到的案例不同。
  1. [oracle@oracle ~]$ sqlplus / as sysdba
  2. Error 6 initializing SQL*Plus
  3. SP2-0667: Message file sp1<lang>.msb not found
  4. SP2-0750: You may need to set ORACLE_HOME to your Oracle software directory
  5. [oracle@oracle ~]$ echo $ORACLE_HOME
  6. /u01/app/oracle/product/11.2.0/db_1
  7. [oracle@oracle ~]$ cat .bash_profile
  8. # .bash_profile

  9. # Get the aliases and functions
  10. if [ -f ~/.bashrc ]; then
  11.     . ~/.bashrc
  12. fi

  13. # User specific environment and startup programs

  14. PATH=$PATH:$HOME/bin

  15. export PATH
  16. export ORACLE_SID=proc
  17. export ORACLE_BASE=/u01/app/oracle
  18. export ORACLE_HOME=$ORACLE_BASE/product/11.2.0/db_1
  19. export PATH=$PATH:$ORACLE_HOME/bin
  20. [oracle@oracle ~]$ which sqlplus
  21. /u01/app/oracle/product/11.2.0/db_1/bin/sqlplus
  22. [oracle@oracle ~]$ oerr sp2 667
  23. oerr: Cannot access the message file /u01/app/oracle/product/11.2.0/db_1/sqlplus/mesg/sp2us.msg
  24. [oracle@oracle ~]$ cd $ORACLE_HOME/sqlplus/mesg
  25. [oracle@oracle mesg]$ ls
報錯是關於ORACLE_HOME環境變數的問題,檢查.bash_profile也沒有發現問題,非常奇怪。
後邊紅色底色的報錯卻是提供了思路,進去指定目錄ls檢視,果然沒有檔案,後邊解決方法就很簡單:
  1. [oracle@oracle mesg]$ cp ~/bak/* ./
  2. [oracle@oracle mesg]$ ll
  3. total 216
  4. -rw-r--r--. 1 oracle oinstall   4096 Dec 30 01:13 cpyus.msb
  5. -rw-r--r--. 1 oracle oinstall   4369 Dec 30 01:13 cpyus.msg
  6. -rw-r--r--. 1 oracle oinstall  12288 Dec 30 01:13 sp1us.msb
  7. -rw-r--r--. 1 oracle oinstall  20123 Dec 30 01:13 sp1us.msg
  8. -rw-r--r--. 1 oracle oinstall  34816 Dec 30 01:13 sp2us.msb
  9. -rw-r--r--. 1 oracle oinstall 137350 Dec 30 01:13 sp2us.msg
  10. [oracle@oracle mesg]$ sqlplus / as sysdba

  11. SQL*Plus: Release 11.2.0.4.0 Production on Fri Dec 30 01:13:38 2016

  12. Copyright (c) 1982, 2013, Oracle. All rights reserved.


  13. Connected to:
  14. Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
  15. With the Partitioning, OLAP, Data Mining and Real Application Testing options

  16. SYS@proc> !oerr sp2 667
  17. 00667, 0, "Message file %s<lang>.msb not found\n"
  18. // *Cause: The SP1, SP2, or CPY message file could not be
  19. // found. SQL*Plus cannot run.
  20. // *Action: Check the Oracle platform specific documentation to make
  21. // sure SQL*Plus is installed correctly. This may occur
  22. // because the ORACLE_HOME environment variable or registry
  23. // equivalent is not set to the location of the Oracle
  24. // software. Make sure this value is set correctly. Check
  25. // that the SQL*Plus binary message files exist in the
  26. // SQL*Plus message directory, for example
  27. // $ORACLE_HOME/sqplus/mesg. Check the value of NLS_LANG
  28. // environment variable or registry equivalent is correct.

  29. SYS@proc>
朋友rac環境的話就是在節點1下該目錄的檔案scp到節點2即解決了問題。
有一個問題是搭建rac的過程為何節點2會缺失檔案,這裡也沒法弄清楚。
該案例的報錯有誤導作用,因為該出並非是由於環境變數而引起的問題。

下邊探究下環境變數引起該問題的情況

資料庫環境:
  1. SYS@proc> select * from v$version where rownum=1;

  2. BANNER
  3. --------------------------------------------------------------------------------
  4. Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

構造之後的故障環境:
  1. [oracle@oracle ~]$ echo $ORACLE_HOME
  2. /u01/app/oracle/product/11.2.0/db_1
  3. [oracle@oracle ~]$ sqlplus / as sysdba
  4. Error 6 initializing SQL*Plus
  5. SP2-0667: Message file sp1<lang>.msb not found
  6. SP2-0750: You may need to set ORACLE_HOME to your Oracle software directory
  7. [oracle@oracle ~]$ ls $ORACLE_HOME/sqlplus/mesg
  8. cpyus.msb cpyus.msg sp1us.msb sp1us.msg sp2us.msb sp2us.msg
  9. [oracle@oracle ~]$
從上邊可以看出,環境變數ORACLE_HOME是有值的,但是使用sqlplus / as sysdba卻報了錯誤,這裡的錯誤非常奇怪。
以下從一般的解決思路入手:
  1. [oracle@oracle ~]$ cat .bash_profile
  2. # .bash_profile

  3. # Get the aliases and functions
  4. if [ -f ~/.bashrc ]; then
  5.     . ~/.bashrc
  6. fi

  7. # User specific environment and startup programs

  8. PATH=$PATH:$HOME/bin

  9. export PATH
  10. export ORACLE_SID=proc
  11. export ORACLE_BASE=/u01/app/oracle
  12.  ORACLE_HOME=$ORACLE_BASE/product/11.2.0/db_1
  13. export PATH=$PATH:$ORACLE_HOME/bin
馬上可以發現,這裡的ORACLE_HOME少了個export關鍵詞,這也是構造故障的做法。
這裡引出兩個疑問:
1.在構造故障的時候,修改完.bash_profile檔案之後,source .bash_profile之後使用sqlplus / as sysdba是不會報錯的,需要重新開啟一個會話。
為什麼?這裡先留作第一個問題。
2.就算是去掉export,echo $ORACLE_HOME還是會有值,為什麼還是報了錯誤。
網友們也可以自己構造環境去思考。
以下是我嘗試解決故障的過程,會有一些不太有用處的過程:
  1. [oracle@oracle ~]$ strace sqlplus
  2. execve("/u01/app/oracle/product/11.2.0/db_1/bin/sqlplus", ["sqlplus"], [/* 35 vars */]) = 0
  3. brk(0) = 0x1533000
  4. mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5f88dab000
  5. access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
  6. open("/u01/app/oracle/product/11.2.0/db_1/lib/tls/x86_64/libsqlplus.so", O_RDONLY) = -1 ENOENT (No such file or directory)
  7. stat("/u01/app/oracle/product/11.2.0/db_1/lib/tls/x86_64", 0x7fff8cb17860) = -1 ENOENT (No such file or directory)
  8. open("/u01/app/oracle/product/11.2.0/db_1/lib/tls/libsqlplus.so", O_RDONLY) = -1 ENOENT (No such file or directory)
  9. stat("/u01/app/oracle/product/11.2.0/db_1/lib/tls", 0x7fff8cb17860) = -1 ENOENT (No such file or directory)
  10. open("/u01/app/oracle/product/11.2.0/db_1/lib/x86_64/libsqlplus.so", O_RDONLY) = -1 ENOENT (No such file or directory)
  11. stat("/u01/app/oracle/product/11.2.0/db_1/lib/x86_64", 0x7fff8cb17860) = -1 ENOENT (No such file or directory)
  12. open("/u01/app/oracle/product/11.2.0/db_1/lib/libsqlplus.so", O_RDONLY) = 3
  13. read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0@\370\1\0\0\0\0\0"..., 832) = 832
  14. fstat(3, {st_mode=S_IFREG|0644, st_size=1469542, ...}) = 0
  15. mmap(NULL, 1985056, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f5f88bc6000
  16. mprotect(0x7f5f88c9c000, 1048576, PROT_NONE) = 0
  17. mmap(0x7f5f88d9c000, 57344, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xd6000) = 0x7f5f88d9c000
  18. mmap(0x7f5f88daa000, 2592, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f5f88daa000
  19. close(3) = 0
  20. open("/u01/app/oracle/product/11.2.0/db_1/lib/libclntsh.so.11.1", O_RDONLY) = 3
  21. read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\326G\0\0\0\0\0"..., 832) = 832
  22. ...省略部分內容...
  23. open("/u01/app/oracle/product/11.2.0/db_1/lib/libsqlplusic.so", O_RDONLY) = -1 ENOENT (No such file or directory)
  24. open("/u01/app/oracle/product/11.2.0/db_1/lib/libociicus.so", O_RDONLY) = -1 ENOENT (No such file or directory)
  25. open("/u01/app/oracle/product/11.2.0/db_1/lib/libociei.so", O_RDONLY) = -1 ENOENT (No such file or directory)
  26. write(2, "Error 6 initializing SQL*Plus\n", 30Error 6 initializing SQL*Plus
  27. ) = 30
  28. write(2, "SP2-0667: Message file sp1<lang>"..., 47SP2-0667: Message file sp1<lang>.msb not found
  29. ) = 47
  30. write(2, "SP2-0750: You may need to set OR"..., 76SP2-0750: You may need to set ORACLE_HOME to your Oracle software directory
  31. ) = 76
  32. exit_group(1) = ?
  1. [oracle@oracle bin]$ strace ./sqlplus
  2. execve("./sqlplus", ["./sqlplus"], [/* 36 vars */]) = 0
  3. brk(0) = 0x1a0d000
  4. mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4f0a3c0000
  5. access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
  6. ...省略部分內容...
  7. open("/u01/app/oracle/product/11.2.0/db_1/lib/libsqlplusic.so", O_RDONLY) = -1 ENOENT (No such file or directory)
  8. open("/u01/app/oracle/product/11.2.0/db_1/lib/libociicus.so", O_RDONLY) = -1 ENOENT (No such file or directory)
  9. open("/u01/app/oracle/product/11.2.0/db_1/lib/libociei.so", O_RDONLY) = -1 ENOENT (No such file or directory)
  10. write(2, "Error 6 initializing SQL*Plus\n", 30Error 6 initializing SQL*Plus
  11. ) = 30
  12. write(2, "SP2-0667: Message file sp1<lang>"..., 47SP2-0667: Message file sp1<lang>.msb not found
  13. ) = 47
  14. write(2, "SP2-0750: You may need to set OR"..., 76SP2-0750: You may need to set ORACLE_HOME to your Oracle software directory
  15. ) = 76
  16. exit_group(1) = ?
1.用strace跟蹤sqlplus後臺程式執行情況,藍底部分對比可以發現,第一處藍底部分的路徑值並不是從ORACLE_HOME獲取的,而是sqlplus命令的所在地址。
2.通過對比正常時候的strace sqlplus輸出文字發現,前邊部分的呼叫文字幾乎相同,除了一些函式的引數值不同。因此strace並不能找出異常時候的資訊,strace並不能更詳細的追蹤出不同之處,比較遺憾。

只能從另外一個角度重新思考了,由於ORACLE_HOME=/u01/app/oracle/product/11.2.0/db_1引起報錯是因為export有無的原因,於是:
  1. [oracle@oracle ~]$ env | grep ORACLE_HOME
  2. [oracle@oracle ~]$ export | grep ORACLE_HOME
  3. [oracle@oracle ~]$ export | grep ORACLE_BASE
  4. declare -x ORACLE_BASE="/u01/app/oracle"
  5. [oracle@oracle ~]$ env | grep ORACLE_BASE
  6. ORACLE_BASE=/u01/app/oracle
  7. [oracle@oracle ~]$ echo $ORACLE_HOME
    /u01/app/oracle/product/11.2.0/db_1
可以發現ORACLE_HOME並沒有在環境變數env中,僅僅只是ORACLE_HOME有值,並且值是“/u01/app/oracle/product/11.2.0/db_1”,難道這個就是原因?
首先,ORACLE從ORACLE_HOME獲取值,而ORACLE_HOME也確實有值,報錯說明這裡的值沒起來作用,於是嘗試通過呼叫指令碼獲取ORACLE_HOME的值,再去觀察結果。
  1. [oracle@oracle piscescanon]$ ll
  2. total 4
  3. -rwxr--r--. 1 oracle oinstall 18 Dec 30 00:32 test.sh
  4. [oracle@oracle piscescanon]$ cat test.sh
  5. echo $ORACLE_HOME
  6. [oracle@oracle piscescanon]$ ./test.sh

結果很明顯,呼叫並不能獲得ORACLE_HOME=/u01/app/oracle/product/11.2.0/db_1的結果。
那麼上邊的兩個問題也很明顯了,第一個問題是因為ORACLE_HOME已經在環境變數裡邊了,就算是更改之後再次source也還是一樣,因此需要重新開啟會話,第二個問題就很明顯了。

從該案例看的話,ORACLE_HOME=/u01/app/oracle/product/11.2.0/db_1,ORACLE_HOME只是區域性變數,區域性變數只對當前shell生效。
而export 
ORACLE_HOME=/u01/app/oracle/product/11.2.0/db_1使得ORACLE_HOME變成系統環境變數,系統環境變數對當前shell以及子shell、子子shell等下一級有效。
  1. [oracle@oracle piscescanon]$ export ORACLE_HOME=/u01/app/oracle/product/11.2.0/db_1
  2. [oracle@oracle piscescanon]$ ./test.sh
  3. /u01/app/oracle/product/11.2.0/db_1

網上的資料:
使用者登入到Linux系統後,系統將啟動一個使用者shell。在這個shell中,可以使用shell命令或宣告變數,也可以建立並執行 shell指令碼程式。執行shell指令碼程式時,系統將建立一個子shell。
此時,系統中將有兩個shell,一個是登入時系統啟動的shell,另一 個是系統為執行指令碼程式建立的shell。當一個指令碼程式執行完畢,它的指令碼shell將終止,可以返回到執行該指令碼之前的shell。
從這種意義上來 說,使用者可以有許多 shell,每個shell都是由某個shell(稱為父shell)派生的。

在子 shell中定義的變數只在該子shell內有效。如果在一個shell指令碼程式中定義了一個變數,當該指令碼程式執行時,這個定義的變數只是該指令碼程式內 的一個區域性變數,其他的shell不能引用它,要使某個變數的值可以在其他shell中被改變,可以使用export命令對已定義的變數進行輸出。
export命令將使系統在建立每一個新的shell時定義這個變數的一個拷貝。這個過程稱之為變數輸出。


對於export和shell的關係,有結論如下:
1、執行指令碼時是在一個子shell環境執行的,指令碼執行完後該子shell自動退出;
2、一個shell中的系統環境變數才會被複制到子 shell中(用export定義的變數);
3、一個shell中的系統環境變數只對該shell或者它的子shell有效,該shell結束時變數消失 (並不能返回到父shell中);
3、不用export定義的變數只對該shell有效,對子shell也是無效的。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30174570/viewspace-2140746/,如需轉載,請註明出處,否則將追究法律責任。

相關文章