bash - 使用 Perl 的 Bash 脚本中出现奇怪的、意外的输出

标签 bash perl shell

我正在尝试编写一个 Bash 脚本,该脚本将在包含多个 C 源文件的文件夹中运行。其中之一将包含 main(),并且还将在顶部包含描述文件/程序及其功能的多行注释。

到目前为止我所拥有的是:

#! /bin/bash
echo "Grepping for main *.c file"
file=$(grep -l main *.c)
echo "the file is ${file}"
comment=$(perl -lne 'print if (/\/\*/ .. /\*\//)' ${file})
echo ${comment}

这告诉我哪个文件包含 main() (在测试用例中,它是 main.c)。然后 perl 函数输出(我认为的)不正确。它不只是在文件中搜索,而是输出

Grepping for main *.c file
the file is main.c
/$RECYCLE.BIN /Applications /Backup /Extra /Extra (from old Mac) 2 /Library /Network /OS X Install Data /System /System Volume Information /Users /Volumes /bin /boot CMakeLists.txt build comment.sh main.c main.dSYM makefile tasksheet.pdf Student Number: n9999999 CMakeLists.txt a1_n9999999 build comment.sh main.c main.dSYM makefile tasksheet.pdf...

后跟文件夹内容的标题,实际的多行注释分散在整个输出中。

如果我尝试cat main.c它输出正确,但如果在 bash 脚本中,我会 echo cat main.ccat ${file}我得到类似类型的垃圾输出。是什么原因造成的?我有一种感觉,这与多行注释包含/* 相关,在 Unix 中它是“根目录中的所有内容”,但是有没有办法解决这个问题?

编辑:运行 perl 命令 perl -lne 'print if (/\/\*/ .. /\*\//)' main.c在终端中输出预期的结果。

最佳答案

您需要双引号 echo:

echo "${comment}"

您会看到 /* 扩展到根目录中的文件列表中。

(你的根目录中有很多不应该存在的碎片。你不应该能够在 / 目录中写入文件。你需要担心你的情况(错误)使用 root 权限。)


请注意,main 的测试实际上不够敏感。包含剩余单词或包含字母 m-a-i-n 序列的许多其他单词中的任何一个的文件将被匹配。然而,这在很大程度上与当前的问题无关。

I'm not very good with grep. Any hints as to how to make the test more robust?

最基本的步骤是使用 grep -l -w main 搜索单词“main”。然而,这会在评论中出现“主要思想是……”等等。我可能会利用有关如何格式化 main() 函数的知识,使用 grep -l -E '^int main\((void|int argc, char\*\*argv )\)$ 来获取 int main(void)int main(int argc, char **argv) — 它们是唯一的签名我曾经使用过,并且将类型与函数放在同一行。如果将 int 放在上一行,则从匹配中删除 int;如果左大括号位于同一行,请修改模式以允许或要求该布局;等等。您可能仍然会遇到“评论中的主要内容”问题,但这不太可能。

我还注意到 Perl 将拾取每个文件中的每个 block 注释,而不是在第一个 block 的末尾停止。大多数源文件中不应该有任何注释。我认为你可以通过以下方式解决这个问题:

perl -ne 'if (/\/\*/ .. /\*\//) { print if ($comment == 0); } ++$comment if m/\*\//;'

我尝试了更紧凑的表示法:

perl -lne 'print if (/\/\*/ .. /\*\// && $comment == 0); ++$comment if m/\*\//'

以及该主题的许多变体,并且 && $comment == 0 条件在功能上被忽略。上面显示的替代方案有效。


好奇心战胜了我。使用“Deparse”模块(SO 搜索“[perl] deparse”)并应用它会显示:

$ perl -MO=Deparse -lne 'print if (/\/\*/ .. /\*\// && $comment == 0); ++$comment if m/\*\//'
BEGIN { $/ = "\n"; $\ = "\n"; }
LINE: while (defined($_ = <ARGV>)) {
    chomp $_;
    print $_ if m[/\*] .. m[\*/] && $comment == 0;
    ++$comment if m[\*/];
}
-e syntax OK
$ perl -MO=Deparse -lne 'print if ((/\/\*/ .. /\*\//) && $comment == 0); ++$comment if m/\*\//'
BEGIN { $/ = "\n"; $\ = "\n"; }
LINE: while (defined($_ = <ARGV>)) {
    chomp $_;
    print $_ if m[/\*] .. m[\*/] and $comment == 0;
    ++$comment if m[\*/];
}
-e syntax OK
$ perl -lne 'print if ((/\/\*/ .. /\*\//) && $comment == 0); ++$comment if m/\*\//'  e2big.c
/* SO 18559403: How big an argument list is allowed */
$

&&的优先级较高; 的值较低。如果您使用范围运算符 ..,请小心并在正确的位置使用大量括号。

关于bash - 使用 Perl 的 Bash 脚本中出现奇怪的、意外的输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32420701/

相关文章:

linux - 使用 awk 查找可变长度的正则表达式并根据找到的长度编辑以下行

linux - 适用于 Linux 和 Solaris 的通用 grep 方法

javascript - 如何忽略 child_process.exec 产生的错误?

bash - 可以在 bash if 语句中使用调用 "test"的函数吗?

linux - 当我运行此代码时,我将获取当前目录中存在的所有文件

linux - Git 推送到 master repo 然后将 dist 文件夹发送到特定路径(/www/site/v0.0.1)?

linux - 从很棒的 wm 运行 scrot -s

xml - 带有 XML::Compile::SOAP::WSS 和 Perl 的 WSSE

html - 使用 CGI 处理表单数据

regex - 在 perl 中,如何模式匹配字符串以查看一行中是否存在回车符