为什么路径名中的下划线会使 Perl 脚本挂起?

Why does underscore in path name make Perl script hang?

我正在对一个 Perl 脚本进行故障排除,该脚本以前从未挂起过,却意外挂起。我不知道珀尔。我终于将问题追溯到文件路径字符串。此代码有效:

$eng_morph = "~/datafile.en.db";
tie %eng_morph, "DB_File", $eng_morph, O_CREAT|O_RDWR, 0664|| die "Cannot open dbmfile $eng_morph";

当我更改文件名以包含下划线时,第二行永远挂起:

$eng_morph = "~/datafile.en_us.db";
tie %eng_morph, "DB_File", $eng_morph, O_CREAT|O_RDWR, 0664|| die "Cannot open dbmfile $eng_morph";

语法有问题吗?有没有办法允许下划线?

我正在使用 Ubuntu 14.04。这是 uname 输出:

Linux asus-notebook 3.13.0-43-generic #72-Ubuntu SMP Mon Dec 8 19:35:06 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

此外,我还在发行版中使用默认的 Perl。它的版本输出是:

This is perl 5, version 18, subversion 2 (v5.18.2) built for x86_64-linux-gnu-thread-multi (with 41 registered patches, see perl -V for more detail)

几乎可以肯定那个特定的数据库文件有问题,而不是文件名。

数据库文件以某种方式损坏,或者服务器上的现有进程打开并锁定了文件。

查看是否有任何其他进程打开了该文件(使用 lsof),并检查名称与数据库相似但以“.”开头的文件。在同一目录中。 (即做 ls -a ~ | grep -i en_us

tie %eng_morph, "DB_File", $eng_morph, O_CREAT|O_RDWR, 0664|| die "Cannot open dbmfile $eng_morph";

需要:

tie %eng_morph, "DB_File", $eng_morph, O_CREAT|O_RDWR, 0664 or die "Cannot open dbmfile $eng_morph";

tie( %eng_morph, "DB_File", $eng_morph, O_CREAT|O_RDWR, 0664 ) || die "Cannot open dbmfile $eng_morph";

因为 || 是高优先级运算符。否则解释为:

tie %eng_morph, "DB_File", $eng_morph, O_CREAT|O_RDWR, ( 0664 || die "Cannot open dbmfile $eng_morph" );

|| 旨在自然地用在 returns 结果的表达式中; or 旨在用于本质上不同的表达式之间的流量控制(尽管两者仅在优先级上不同)。

由于这个错误,当平局失败时,您不会死,代码继续 运行,但将 %eng_morph 保留为正常的未平局哈希。

这个问题是间歇性的。事实证明这是一个线程问题——许多间歇性问题都是如此。线索是输出文件夹中存在一个奇怪的文件:"~/_db_datafile.en.db" ... 或任何以 "~/_db_" 为前缀的已定义输出文件名。当所需的输出文件应该为 2 或 3 兆字节时,此输出文件的范围为 0 到 14K 字节。看起来 Perl tie() 函数在创建数据库文件时被中断了。

有问题的代码是从 Python 脚本调用的,该脚本使用带有 subprocess.Popen() 管道的非阻塞线程。 Python 脚本生成 Perl 脚本并继续其流程。当 Perl 脚本仍在创建数据库文件时,Python 的非阻塞线程开始传输数据。这会停止 Perl 脚本的文件创建并导致锁定。

文件名中的下划线只是此错误的第一个间歇性实例,最终与问题无关。

解决方案是简单地在 Python 代码中创建一个 while not os.path.exists(eng_morph): 循环以暂停,直到存在正确的数据库文件。