我正在向 C++ 代码添加自测试,以确保不存在NDEBUG
Posix 断言依赖项(下面的背景故事)。第一个测试寻找包含<assert.h>
和<cassert>
:
FAILED=0
COUNT=$($EGREP -c '(assert.h|cassert)' *.h *.cpp)
if [[ "$COUNT" -ne "0" ]]; then
FAILED=1
echo "Found Posix assert headers" | tee -a "$TEST_RESULTS"
fi
其生产:
************************************
Testing: No Posix assert
./cryptest.sh: line 1130: [[: 3way: value too great for base (error token is "3way")
...
当我调试它时,我看到:
bash -x ./cryptest.sh
...
++ egrep -c '(assert.h|cassert)' 3way.h adler32.h aes.h ...
+ COUNT='3way.h:0
adler32.h:0
aes.h:0
...
因此每个文件都有自己的行和计数。
这grep
手册页陈述如下。它不讨论多行输出。
-c, --count
Only a count of selected lines is written to standard output.
该行为似乎与输出控制(构成手册页)和-l, --files-with-matches
.我也尝试过这个-L, --files-without-match
选项。它会产生类似的错误。
我的问题是,如何将grep
结果合并为一个计数?
或者也许我应该问,grep 和egrep 是适合这项工作的工具吗?如果 grep 和egrep 不是合适的工具,那么我应该使用什么?
这是一个 Bash shell 脚本,可以在我们支持的每个平台上执行。每个平台都包括 BSD、Linux、OS X、Solaris 和 Unix(以及所有移动版本,如 Android 和 iOS)。我们必须努力获得我们所需要的工具,例如grep
和egrep
:
GREP=grep
EGREP=egrep
SED=sed
AWK=awk
DISASS=objdump
DISASSARGS=("--disassemble")
...
# Fixup
if [[ "$IS_SOLARIS" -ne "0" ]]; then
IS_X64=$(isainfo 2>/dev/null | "$GREP" -i -c "amd64")
if [[ "$IS_X64" -ne "0" ]]; then
IS_X86=0
fi
# Need something more powerful than the non-Posix versions
if [[ (-e "/usr/gnu/bin/grep") ]]; then
GREP=/usr/gnu/bin/grep;
fi
if [[ (-e "/usr/gnu/bin/egrep") ]]; then
EGREP=/usr/gnu/bin/egrep;
fi
if [[ (-e "/usr/gnu/bin/sed") ]]; then
SED=/usr/gnu/bin/sed;
fi
if [[ (-e "/usr/gnu/bin/awk") ]]; then
AWK=/usr/gnu/bin/awk;
else
AWK=nawk;
fi
DISASS=dis
DISASSARGS=()
fi
...
背景故事
我们的项目最近采取了CVE-2016-7420由于用户使用其他工具(例如 Autotools 和 CMake)构建项目。 CVE 是-DNDEBUG
省略发布/生产版本的直接结果。其他工具的配置方式与我们不同,我们也没有告诉用户 (1) 他们不能使用其他构建工具,或者 (2) 用户必须定义-DNDEBUG
发布/生产。
我们的补救措施NDEBUG
比文档中的“简单地定义发布/生产”要深入得多。我们是NDEBUG
消除对Posix 的所有依赖assert
所以人们不会意外地进入配置。我们还要求用户通过定义DEBUG
或 来请求调试配置_DEBUG
;否则,他们将获得发布配置。
虽然后面的assert
和SIGART
通常在发布版本中很烦人,但在调试版本中被认为是良性的,并且被认为是理所当然的,但我们观察到:
- 我们是一个安全图书馆(我们处理敏感信息)
- 失败的断言会将敏感信息传出到文件系统(核心文件和崩溃报告)
- 失败的断言会将敏感信息泄露给 Apple (CrashReporter)、Apport (Ubuntu)、Microsoft (Windows 错误报告) 等平台供应商
- 苹果、谷歌和微软等公司与政府合作挖掘敏感信息
答案1
注意:以下内容基于 的 GNU 实现grep
,但我认为它也应该适用于您的情况
正如 GNUgrep
手册中所述(重点是我的)
grep searches the named input FILEs for lines containing a match to the
given PATTERN. If no files are specified, or if the file “-” is given,
grep searches standard input. By default, grep prints the matching
lines.
还,
-c, --count
Suppress normal output; instead print a count of matching lines
**for each input file**. With the -v, --invert-match option (see
below), count non-matching lines.
(默认行为是在此类输出中添加文件名前缀 - 尽管可以使用该-h
选项来抑制)。
通过将目标文件连接到单个输入流并将其传输到grep
,您应该能够覆盖这两种行为并获得不带前缀的单个计数:
COUNT=$(cat *.h *.cpp | $EGREP -c '(assert.h|cassert)')
恕我直言,这将有资格作为有用使用猫;可能你被建议反对的是猫的无用使用
答案2
钢铁司机的回答当我读到你的问题标题时, (do )是我的第一个想法。但我发现,在您的脚本片段中,除了将其与零进行比较之外,您没有使用计数 - 即,您问“有多少个?”当你想知道“有吗?”时。考虑使用:cat files | grep -c <token>
-q
if "$EGREP" -q -- 'assert\.h|cassert' *.h *.cpp
then
FAILED=1
echo "Found Posix assert headers" …
fi
笔记:
- 您应该始终引用您的 shell 变量引用(例如,
"$EGREP"
),除非您有充分的理由不这样做,并且您确定您知道自己在做什么。如果您已经定义了EGREP=grep -e
,那么这将是一个不带引号的合理理由$EGREP
,但请参阅这个答案到忘记在 bash/POSIX shell 中引用变量的安全隐患。 -q
(或,等效地,--quiet
或--silent
)表示“安静;不要向标准输出写入任何内容。如果发现任何匹配,即使检测到错误,也会立即以零状态退出。”这不仅为您提供了所需的功能行为(即与 Steeldriver 的答案相同的功能行为),而且具有grep
一旦找到匹配项就会退出的性能优势,并且不需要读取所有文件。- 建议将其放在
--
命令的选项及其参数之间,以防止以 开头的文件名-
被解释为选项字符串。 - 整个正则表达式不需要用括号括起来。
grep 'assert.h'
将匹配assert h
、assert,h
、assert3h
、assertph
等。如果您不在乎,那由您决定。如果您只想匹配assert.h
,请 grep forassert\.h
。