我有很多 Windows 计算机,需要删除并重新安装 Oracle 数据库客户端。我遇到的问题是安装它们的人都使用
C:\Program Files\Oracle\Database Client\21.0.0
作为 $ORACLE_HOME
目录而不是默认的 C:\app
。 Oracle 的内置卸载程序无法处理包含空格的文件路径。
卸载一个简单的批处理文件,该文件调用几个 Perl 脚本,并以
$ORACLE_HOME
作为参数,所以我决定手动调用 bootstrap.pl
,这就是我得到的:
C:\>"C:\Program Files\Oracle\Database Client\21.0.0\perl\bin\perl.exe" "C:\Program Files\Oracle\Database Client\21.0.0\deinstall\bootstrap.pl" 1 ^"C:\Program Files\Oracle\Database Client\21.0.0^"
18 File(s) copied
Invalid number of parameters
Bootstrap Failed. at C:\Program Files\Oracle\Database Client\21.0.0\deinstall\bootstrap.pl line 148
*请注意,上面命令行中的脱字号 (^) 需要转义双引号。否则,你最终会以
C:\Program
作为参数。
以下是
bootstrap.pl
脚本中的相关代码行:
my @sourceDirs = ($dest.$dirSep.'deinstall',$ORACLE_HOME.$dirSep.'oui',$ORACLE_HOME.$dirSep.'perl',$ORACLE_HOME.$dirSep.'jdk',$ORACLE_HOME.$dirSep.'oracle_common');
if($giHomeCleanFound == 0)
{
if ( $^O eq "MSWin32" ) {
system("xcopy /y/s/i/e/q $sourceDirs[0] $dest") == 0 or die "Bootstrap Failed.";
print $ORACLE_HOME.$dirSep.'oui'; #<-- I added this statement to see what the sting looks like
system("xcopy /y/s/i/e/q $sourceDirs[1] $dest\\oui") == 0 or die "Bootstrap Failed."; #<-- This is the line where it fails
system("xcopy /y/s/i/e/q $sourceDirs[2] $dest\\perl") == 0 or die "Bootstrap Failed.";
system("xcopy /y/s/i/e/q $sourceDirs[3] $dest\\jdk") == 0 or die "Bootstrap Failed.";
if ($nextGen eq "true") {
system("xcopy /y/s/i/e/q $sourceDirs[4] $dest\\oracle_common") == 0 or die "Bootstrap Failed.";
}
}
实际上,Perl 脚本只是将工作发送回命令行。这基本上是双引号没有正确转义的恶性循环。这只是 Perl 脚本之一的一个块,所以我确信这种代码无处不在。我真的不想为他们重写 Oracle 的脚本。我曾经尝试编写 Oracle 的手动删除指令脚本,但进展并不顺利。
有没有办法从命令行转义双引号,以便从 Perl 脚本传回命令行时可以正确转义双引号?
或者有没有更好的工具可以干净地删除客户端?
如果您只是想卸载这些东西,那么修复 perl 可能不值得。您可以看到它正在尝试执行的操作,然后手动执行即可。然后你继续生活。有时,我还发现,当这是一件不需要未来关注的一次性事情时,将空间从路径中移出会更容易。
现在,谈谈一些有趣的观点。
我不玩Oracle,所以我只是回应总体想法。而且,如果 bootstrap.pl 是由 Oracle 提供的,也许您可以赢得 bug 赏金(如果他们甚至这样做的话)。
一般来说,不要从用户输入(或外部源)创建命令字符串,然后将大字符串交给
system
。有时我们会出于各种安全考虑而谈论这一点。例如,如果有人可以搞乱决定最终在 @sourcedirs
中的路径的各种输入,他们可能能够在该 system
中执行其他 DOS 命令。我在《掌握 Perl》的安全章节中介绍了这类内容,并且很多人在其他地方写过相关内容,所以我们就不再赘述了。 perlsec 也是一本好书。
作为奖励,如果您正在玩 Perl Bar 琐事,这里还有一些其他奇怪的事情。
File::Spec::catfile
$dirsep
的情况下创建路径。目录分隔符位于 perl 配置中。$ perl -V:path_sep
path_sep=';'
$ perl -MConfig -le "print $Config{path_sep}"
;
我们需要更多地讨论路径中的空间。不知何故,路径中空格的想法还没有跟上编程实践的步伐。我们都知道在编写代码之前可能会有空格。
@ikegami 已经指出了
Win32::Shellquote。我还有 Perl.com 文章“引用 Shell”:
use Win32::ShellQuote qw(:all);
system quote_system( qw(xcopy /y/s/i/e/q), $sourceDirs[0], $dest );
还有多种其他方法可以引用 Win32 shell 命令,具体取决于您想要执行的操作。