一、問題背景
最近接手的Oracle數(shù)據(jù)庫比較多,但是Oracle 的 sqlplus 客戶端默認(rèn)不支持方向鍵查看歷史命令的功能,也不支持backspace回退鍵,很不友好,嚴(yán)重影響工作效率。相信很多人在使用sqlplus的時(shí)候看到過類似的亂碼提示:
SQL> select sysdate from dual;
SYSDATE
---------
14-SEP-25
--按上下方向鍵提示:
SQL> ^[[A " - rest of line ignored.
SQL> 042: unknown command "
SQL>
SQL>
--按backspace鍵提示:
SQL> select a ^H^H^H^H
2
SQL> exit
接下來詳細(xì)介紹使用readline和rlwrap實(shí)現(xiàn)上下方向鍵查看歷史命令以及正常使用backspace回退鍵的方法,實(shí)現(xiàn) sqlplus 命令行的流暢操作。
二、分步操作步驟
1、安裝readline依賴包
readline 提供命令行編輯與歷史記錄功能,是 rlwrap 的核心依賴。
yum install readline*
## 檢查已安裝的readline包
rpm -qa|grep readline
操作過程如下:
[root@node3 yum.repos.d]# yum install readline*
Loaded plugins: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
* base: mirrors.aliyun.com
* extras: mirrors.aliyun.com
* updates: mirrors.aliyun.com
Package readline-6.2-11.el7.x86_64 already installed and latest version
Package readline-devel-6.2-11.el7.x86_64 already installed and latest version
Resolving Dependencies
--> Running transaction check
---> Package readline-static.x86_64 0:6.2-11.el7 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
================================================================================================================================================================================================================================================================
Package Arch Version Repository Size
================================================================================================================================================================================================================================================================
Installing:
readline-static x86_64 6.2-11.el7 base 118 k
Transaction Summary
================================================================================================================================================================================================================================================================
Install 1 Package
Total download size: 118 k
Installed size: 550 k
Is this ok [y/d/N]: y
Downloading packages:
readline-static-6.2-11.el7.x86_64.rpm | 118 kB 00:00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Warning: RPMDB altered outside of yum.
Installing : readline-static-6.2-11.el7.x86_64 1/1
Verifying : readline-static-6.2-11.el7.x86_64 1/1
Installed:
readline-static.x86_64 0:6.2-11.el7
Complete!
## 檢查已安裝的readline包
[root@node3 yum.repos.d]# rpm -qa|grep readline
readline-static-6.2-11.el7.x86_64
readline-devel-6.2-11.el7.x86_64
readline-6.2-11.el7.x86_64
[root@node3 yum.repos.d]#
2、安裝wlwrap包
rlwrap 是命令行包裝工具,可給 sqlplus 附加方向鍵功能,需源碼編譯安裝。
cd /soft
##下載wlwrap包
wget https://github.com/hanslub42/rlwrap/archive/refs/heads/master.zip
unzip rlwrap-master.zip -d rlwrap
cd /soft/rlwrap/rlwrap-master
yum install -y autoconf automake ##系統(tǒng)中不存在時(shí)安裝
autoreconf --install
./configure
make
make install
安裝過程如下:
[root@node3 soft]# rpm -qa|grep autoconf autoconf-2.69-11.el7.noarch [root@node3 soft]# rpm -qa|grep automake automake-1.13.4-3.el7.noarch [root@node3 soft]# ls rlwrap rlwrap-master.zip [root@node3 soft]# cd rlwrap/ [root@node3 rlwrap]# ls rlwrap-master [root@node3 rlwrap]# cd rlwrap-master/ [root@node3 rlwrap-master]# ls AUTHORS BUGS ChangeLog completions configure.ac COPYING doc filters INSTALL Makefile.am NEWS README.md src test [root@node3 rlwrap-master]# autoreconf --install configure.ac:32: installing 'tools/config.guess' configure.ac:32: installing 'tools/config.sub' configure.ac:34: installing 'tools/install-sh' configure.ac:34: installing 'tools/missing' parallel-tests: installing 'tools/test-driver' src/Makefile.am: installing 'tools/depcomp' [root@node3 rlwrap-master]# ls aclocal.m4 AUTHORS autom4te.cache BUGS ChangeLog completions config.h.in configure configure.ac COPYING doc filters INSTALL Makefile.am Makefile.in NEWS README.md src test tools [root@node3 rlwrap-master]# [root@node3 rlwrap-master]# ./configure checking build system type... x86_64-unknown-linux-gnu checking host system type... x86_64-unknown-linux-gnu checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /usr/bin/mkdir -p checking for gawk... gawk checking whether make sets $(MAKE)... yes checking whether make supports nested variables... yes checking whether make sets $(MAKE)... (cached) yes checking whether build environment is sane... yes checking for style of include used by make... GNU checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking dependency style of gcc... gcc3 checking for ptytty_create in -lptytty... no configure: error: libptytty not found, install it or specify --without-libptytty ######此處報(bào)錯(cuò) [root@node3 rlwrap-master]# [root@node3 rlwrap-master]# ./configure --without-libptytty checking build system type... x86_64-unknown-linux-gnu checking host system type... x86_64-unknown-linux-gnu checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /usr/bin/mkdir -p checking for gawk... gawk checking whether make sets $(MAKE)... yes checking whether make supports nested variables... yes checking whether make sets $(MAKE)... (cached) yes checking whether build environment is sane... yes checking for style of include used by make... GNU checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking dependency style of gcc... gcc3 checking for ptytty_create in -lptytty... no checking for gcc... (cached) gcc checking whether we are using the GNU C compiler... (cached) yes checking whether gcc accepts -g... (cached) yes checking for gcc option to accept ISO C89... (cached) none needed checking dependency style of gcc... (cached) gcc3 checking how to run the C preprocessor... gcc -E checking for perl... /usr/bin/perl checking for strip... strip checking for sys/wait.h that is POSIX.1 compatible... yes checking for grep that handles long lines and -e... /usr/bin/grep checking for egrep... /usr/bin/grep -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking errno.h usability... yes checking errno.h presence... yes checking for errno.h... yes checking fcntl.h usability... yes checking fcntl.h presence... yes checking for fcntl.h... yes checking libgen.h usability... yes checking libgen.h presence... yes checking for libgen.h... yes checking libutil.h usability... no checking libutil.h presence... no checking for libutil.h... no checking for stdlib.h... (cached) yes checking for string.h... (cached) yes checking sched.h usability... yes checking sched.h presence... yes checking for sched.h... yes checking sys/file.h usability... yes checking sys/file.h presence... yes checking for sys/file.h... yes checking sys/ioctl.h usability... yes checking sys/ioctl.h presence... yes checking for sys/ioctl.h... yes checking for sys/wait.h... (cached) yes checking sys/resource.h usability... yes checking sys/resource.h presence... yes checking for sys/resource.h... yes checking stddef.h usability... yes checking stddef.h presence... yes checking for stddef.h... yes checking termios.h usability... yes checking termios.h presence... yes checking for termios.h... yes checking for unistd.h... (cached) yes checking for stdint.h... (cached) yes checking time.h usability... yes checking time.h presence... yes checking for time.h... yes checking sys/time.h usability... yes checking sys/time.h presence... yes checking for sys/time.h... yes checking getopt.h usability... yes checking getopt.h presence... yes checking for getopt.h... yes checking regex.h usability... yes checking regex.h presence... yes checking for regex.h... yes checking curses.h usability... yes checking curses.h presence... yes checking for curses.h... yes checking stropts.h usability... no checking stropts.h presence... no checking for stropts.h... no checking termcap.h usability... yes checking termcap.h presence... yes checking for termcap.h... yes checking util.h usability... no checking util.h presence... no checking for util.h... no checking stdarg.h usability... yes checking stdarg.h presence... yes checking for stdarg.h... yes checking for term.h... yes checking for ncurses/term.h... yes checking whether PROC_PIDVNODEPATHINFO is declared... no checking whether procstat_open_sysctl is declared... no checking whether procstat_getprocs is declared... no checking whether procstat_getfiles is declared... no checking whether STAILQ_FOREACH is declared... no checking argument type of tputs putc function... int checking for an ANSI C-conforming const... yes checking for pid_t... yes checking for getopt_long... yes checking for basename... yes checking for dirname... yes checking for flock... yes checking for getopt_long... (cached) yes checking for isastream... yes checking for pselect... yes checking for sched_yield... yes checking for setitimer... yes checking for setsid... yes checking for setrlimit... yes checking for sigaction... yes checking for system... yes checking whether mkstemps is declared... yes checking whether snprintf is declared... yes checking whether strlcat is declared... no checking whether strnlen is declared... yes checking whether setenv is declared... yes checking whether putenv is declared... yes checking whether readlink is declared... yes checking whether nice is declared... yes checking for openpty in -lutil... yes checking for openpty... yes checking for getpty... no checking for grantpt... yes checking for unlockpt... yes checking for getpt... checking for pty/tty type... checking pty.h usability... yes checking pty.h presence... yes checking for pty.h... yes OPENPTY configure: checking for pty ranges checking for tgetent... no checking for tgetent in -ltinfo... yes checking for readline in -lreadline... yes checking for tigetnum... yes checking readline/readline.h usability... yes checking readline/readline.h presence... yes checking for readline/readline.h... yes checking whether your readline headers and library know about rl_set_screen_size... yes checking whether your readline headers and library know about rl_basic_quote_characters... yes checking whether your readline headers and library know about rl_variable_value... yes checking whether your readline headers and library know about rl_readline_version... yes checking whether your readline headers and library know about rl_executing_keyseq... no checking whether the private symbol _rl_horizontal_scroll_mode is visble in your readline libs... yes Will rlwrap find command's working directory under /proc/<commands pid>/cwd? let's see... checking for /proc/67789/cwd/configure.ac... yes checking whether we can find command line under <opt_proc_mountpoint>/<pid>/cmdline and mirror it by overwriting our own *argv (this may take a few secs)... yes Trying to backdate src/completion.rb a few secs in order to prevent a spurious call to a (possibly not installed) helper 'rbgen' checking that generated files are newer than configure... done checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating filters/Makefile config.status: creating doc/Makefile config.status: creating src/Makefile config.status: creating doc/rlwrap.man config.status: creating config.h config.status: executing depfiles commands Now do: make (or gmake) to build rlwrap make check for instructions how to test it make install to install it [root@node3 rlwrap-master]# make make all-recursive make[1]: Entering directory `/soft/rlwrap/rlwrap-master' Making all in doc make[2]: Entering directory `/soft/rlwrap/rlwrap-master/doc' sed -e 's#@DATADIR@#/usr/local/share#' rlwrap.man > rlwrap.1 make[2]: Leaving directory `/soft/rlwrap/rlwrap-master/doc' Making all in src make[2]: Entering directory `/soft/rlwrap/rlwrap-master/src' gcc -DHAVE_CONFIG_H -I. -I.. -DDATADIR=\"/usr/local/share\" -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c mv -f .deps/main.Tpo .deps/main.Po gcc -DHAVE_CONFIG_H -I. -I.. -DDATADIR=\"/usr/local/share\" -g -O2 -MT signals.o -MD -MP -MF .deps/signals.Tpo -c -o signals.o signals.c mv -f .deps/signals.Tpo .deps/signals.Po gcc -DHAVE_CONFIG_H -I. -I.. -DDATADIR=\"/usr/local/share\" -g -O2 -MT readline.o -MD -MP -MF .deps/readline.Tpo -c -o readline.o readline.c mv -f .deps/readline.Tpo .deps/readline.Po gcc -DHAVE_CONFIG_H -I. -I.. -DDATADIR=\"/usr/local/share\" -g -O2 -MT pty.o -MD -MP -MF .deps/pty.Tpo -c -o pty.o pty.c mv -f .deps/pty.Tpo .deps/pty.Po gcc -DHAVE_CONFIG_H -I. -I.. -DDATADIR=\"/usr/local/share\" -g -O2 -MT completion.o -MD -MP -MF .deps/completion.Tpo -c -o completion.o completion.c mv -f .deps/completion.Tpo .deps/completion.Po gcc -DHAVE_CONFIG_H -I. -I.. -DDATADIR=\"/usr/local/share\" -g -O2 -MT term.o -MD -MP -MF .deps/term.Tpo -c -o term.o term.c mv -f .deps/term.Tpo .deps/term.Po gcc -DHAVE_CONFIG_H -I. -I.. -DDATADIR=\"/usr/local/share\" -g -O2 -MT ptytty.o -MD -MP -MF .deps/ptytty.Tpo -c -o ptytty.o ptytty.c mv -f .deps/ptytty.Tpo .deps/ptytty.Po gcc -DHAVE_CONFIG_H -I. -I.. -DDATADIR=\"/usr/local/share\" -g -O2 -MT utils.o -MD -MP -MF .deps/utils.Tpo -c -o utils.o utils.c mv -f .deps/utils.Tpo .deps/utils.Po gcc -DHAVE_CONFIG_H -I. -I.. -DDATADIR=\"/usr/local/share\" -g -O2 -MT string_utils.o -MD -MP -MF .deps/string_utils.Tpo -c -o string_utils.o string_utils.c mv -f .deps/string_utils.Tpo .deps/string_utils.Po gcc -DHAVE_CONFIG_H -I. -I.. -DDATADIR=\"/usr/local/share\" -g -O2 -MT malloc_debug.o -MD -MP -MF .deps/malloc_debug.Tpo -c -o malloc_debug.o malloc_debug.c mv -f .deps/malloc_debug.Tpo .deps/malloc_debug.Po gcc -DHAVE_CONFIG_H -I. -I.. -DDATADIR=\"/usr/local/share\" -g -O2 -MT multibyte.o -MD -MP -MF .deps/multibyte.Tpo -c -o multibyte.o multibyte.c mv -f .deps/multibyte.Tpo .deps/multibyte.Po gcc -DHAVE_CONFIG_H -I. -I.. -DDATADIR=\"/usr/local/share\" -g -O2 -MT filter.o -MD -MP -MF .deps/filter.Tpo -c -o filter.o filter.c mv -f .deps/filter.Tpo .deps/filter.Po gcc -DDATADIR=\"/usr/local/share\" -g -O2 -o rlwrap main.o signals.o readline.o pty.o completion.o term.o ptytty.o utils.o string_utils.o malloc_debug.o multibyte.o filter.o -lutil -lreadline -ltinfo make[2]: Leaving directory `/soft/rlwrap/rlwrap-master/src' Making all in filters make[2]: Entering directory `/soft/rlwrap/rlwrap-master/filters' pod2man --section=3pm RlwrapFilter.pm > RlwrapFilter.3pm make[2]: Leaving directory `/soft/rlwrap/rlwrap-master/filters' make[2]: Entering directory `/soft/rlwrap/rlwrap-master' make[2]: Leaving directory `/soft/rlwrap/rlwrap-master' make[1]: Leaving directory `/soft/rlwrap/rlwrap-master' [root@node3 rlwrap-master]# make install Making install in doc make[1]: Entering directory `/soft/rlwrap/rlwrap-master/doc' make[2]: Entering directory `/soft/rlwrap/rlwrap-master/doc' make[2]: Nothing to be done for `install-exec-am'. /usr/bin/mkdir -p '/usr/local/share/man/man1' /usr/bin/install -c -m 644 rlwrap.1 '/usr/local/share/man/man1' make[2]: Leaving directory `/soft/rlwrap/rlwrap-master/doc' make[1]: Leaving directory `/soft/rlwrap/rlwrap-master/doc' Making install in src make[1]: Entering directory `/soft/rlwrap/rlwrap-master/src' make[2]: Entering directory `/soft/rlwrap/rlwrap-master/src' /usr/bin/mkdir -p '/usr/local/bin' /usr/bin/install -c rlwrap '/usr/local/bin' make[2]: Nothing to be done for `install-data-am'. make[2]: Leaving directory `/soft/rlwrap/rlwrap-master/src' make[1]: Leaving directory `/soft/rlwrap/rlwrap-master/src' Making install in filters make[1]: Entering directory `/soft/rlwrap/rlwrap-master/filters' make[2]: Entering directory `/soft/rlwrap/rlwrap-master/filters' make[2]: Nothing to be done for `install-exec-am'. /usr/bin/mkdir -p '/usr/local/share/man/man3' /usr/bin/install -c -m 644 RlwrapFilter.3pm '/usr/local/share/man/man3' make[2]: Leaving directory `/soft/rlwrap/rlwrap-master/filters' make[1]: Leaving directory `/soft/rlwrap/rlwrap-master/filters' make[1]: Entering directory `/soft/rlwrap/rlwrap-master' make[2]: Entering directory `/soft/rlwrap/rlwrap-master' make[2]: Nothing to be done for `install-exec-am'. /usr/bin/mkdir -p '/usr/local/share/rlwrap' /usr/bin/mkdir -p '/usr/local/share/rlwrap/filters' /usr/bin/install -c -m 644 filters/README filters/RlwrapFilter.pm filters/RlwrapFilter.3pm filters/count_in_prompt filters/pipeto filters/logger filters/null filters/unbackspace filters/pipeline filters/ftp_filter filters/handle_hotkeys filters/history_format filters/simple_macro filters/template filters/scrub_prompt filters/paint_prompt filters/censor_passwords filters/listing filters/paint_prompt.py filters/handle_hotkeys.py filters/logger.py filters/pipeto.py filters/rlwrapfilter.py filters/null.py filters/censor_passwords.py filters/edit_history filters/count_in_prompt.py filters/ftp_filter.py filters/debug_null filters/handle_sigwinch filters/outfilter filters/makefilter filters/dissect_prompt filters/nl_and_then_prompt.py '/usr/local/share/rlwrap/filters' /usr/bin/mkdir -p '/usr/local/share/rlwrap/completions' /usr/bin/install -c -m 644 completions/testclient completions/coqtop '/usr/local/share/rlwrap/completions' make install-data-hook make[3]: Entering directory `/soft/rlwrap/rlwrap-master' chmod a+x /usr/local/share/rlwrap/filters/* make[3]: Leaving directory `/soft/rlwrap/rlwrap-master' make[2]: Leaving directory `/soft/rlwrap/rlwrap-master' make[1]: Leaving directory `/soft/rlwrap/rlwrap-master'
3、查看rlwrap的路徑
[root@node3 rlwrap-master]# which rlwrap /usr/local/bin/rlwrap
4、配置oracle用戶環(huán)境變量
通過別名(alias)讓 Oracle 用戶啟動(dòng) sqlplus 時(shí)自動(dòng)加載 rlwrap,無需每次手動(dòng)輸入。
cat >> /home/oracle/.bash_profile<<EOF alias sqlplus='/usr/local/bin/rlwrap /data/app/oracle/product/19.3.0/db/bin/sqlplus' EOF source /home/oracle/.bash_profile
到現(xiàn)在為止,在sqlplus客戶端工具中已經(jīng)可以實(shí)現(xiàn)自由翻頁了。
5、功能驗(yàn)證
- 啟動(dòng) sqlplus:
sqlplus 用戶名/密碼@數(shù)據(jù)庫實(shí)例名
- 測(cè)試功能:
- 按 上/下方向鍵:查看歷史執(zhí)行命令。
- 按 Backspace 鍵:刪除光標(biāo)前的字符。
- 無亂碼提示即配置成功。
三、常見問題解決
| 問題現(xiàn)象 | 原因 | 解決方案 |
|---|---|---|
執(zhí)行 ./configure 時(shí)報(bào) libptytty not found |
缺少 libptytty 依賴庫 | 重新執(zhí)行 ./configure --without-libptytty(跳過該依賴) |
啟動(dòng) sqlplus 提示 rlwrap: command not found |
rlwrap 路徑未加入環(huán)境變量 | 直接使用絕對(duì)路徑(如 /usr/local/bin/rlwrap),或執(zhí)行 echo 'export PATH=$PATH:/usr/local/bin' >> ~/.bash_profile |
| 別名不生效 | 未執(zhí)行 source 命令,或編輯了錯(cuò)誤的環(huán)境變量文件 |
執(zhí)行 source ~/.bash_profile,確認(rèn)文件為 Oracle 用戶的 ~/.bash_profile(非 root 用戶) |
四、總結(jié)
通過“安裝readline依賴 → 編譯rlwrap工具 → 配置sqlplus別名”三步,可快速解決 sqlplus 方向鍵、backspace回退鍵失效問題。配置后,sqlplus 操作體驗(yàn)與 Linux 原生命令行一致,大幅提升 SQL 編寫與調(diào)試效率。趕快試試吧!
關(guān)于作者
網(wǎng)名:飛天,墨天輪2024年度優(yōu)秀原創(chuàng)作者,擁有 Oracle 10g OCM 認(rèn)證、PGCE認(rèn)證、MySQL 8.0 OCP認(rèn)證以及OBCA、KCP、KCSM、ACP、YCP、磐維等眾多國產(chǎn)數(shù)據(jù)庫認(rèn)證證書,目前從事Oracle、Mysql、PostgresSQL、磐維數(shù)據(jù)庫管理運(yùn)維工作,喜歡結(jié)交更多志同道合的朋友,熱衷于研究、分享數(shù)據(jù)庫技術(shù)。
微信公眾號(hào):飛天online
墨天輪:http://www.sunline.cc/u/15197
如有任何疑問,歡迎大家留言,共同探討~~~




