如何打印包含该字符串的最后 3 行#include
,tester.c
如果包含该字符串的行少于 3 行,则打印整个文件。
到目前为止我已经:
grep "#include" tester.c | tail -3
但我不知道如何包含要求的后半部分。这是家庭作业,解决方案必须是一行,没有,;
这就是为什么我似乎无法弄清楚。
答案1
tail -3
不会打印超过 3 行;它打印 3 个或更少。因此,如果 'grep' 找到 3 个或更少的匹配行,tail 会将它们全部传递到标准输出。如果匹配项超过 3 个,tail
则将其限制为仅 3 行。
您甚至在将问题发布到此处之前就已经解决了您的问题,因为您的命令正是您所需要的......
这就是你晚上工作时会发生的事情:)
编辑:我可能误读了你的问题..
如果您想在找到 <3 个匹配项时打印整个文件 - 只需运行
f="testfile.c" && C=3 && [ $(grep -c "#include" ${f}) -lt ${C} ] && cat ${f} || grep "#include" ${f} |tail -${C}
但是,如果您正在处理可能较慢的 FS(例如 NFS),或者您正在处理具有大量行或行非常长的文件,那么这对您来说可能太慢了,因为您必须读取该文件两次。
f="testfile.c" && C=3 && CONTENT=$(cat "${f}") && MATCHES=$(echo "$CONTENT"|grep "#include"|tail -${C}) && [ $(echo "$MATCHES" | wc -l) -lt ${C} ] && echo "$CONTENT" || echo "$MATCHES"
这样,您只需打开并读取文件一次,但您会将其缓冲在 RAM 中(这比存储设备快得多)。如果您的 RAM 不足或缓冲文件对您来说太昂贵,请使用第一个命令 [其中文件被打开两次];它速度较慢,但不会使操作系统或您的应用程序崩溃(尽管进程陷入“D”状态的风险更高......而且这对操作系统也没有好处......)
答案2
你可以像 Sildoreth 所说的那样做,不需要“;”像这样:
test $(echo `grep "#include" tester.c` | wc -l) -ge 3 && {echo `grep "#include" tester.c` | head -n 3} || cat tester.c
答案3
这是一个奇怪的问题,特别是考虑到您在原始帖子中提出的命令正是您想要的?
例如,在 file.c 中,有 15 行与 grep 表达式匹配:
% grep -c "#include" file.c 15 % grep "#include" file.c | head -18 #(more than the number of matches) #include <sys/blah.h> #include <sys/blah2.h> #include <sys/blah3.h> #include <sys/blah4.h> #include <sys/blah5.h> #include <sys/blah6.h> #include <sys/blah7.h> #include <sys/blah8.h> #include <sys/blah9.h> #include <sys/blah10.h> #include <sys/blah11.h> #include <sys/blah12.h> #include <sys/blah13.h> #include <sys/blah14.h> #include <sys/blah15.h>
或者
% grep "#include" file.c | tail -18 #include <sys/blah.h> #include <sys/blah2.h> #include <sys/blah3.h> #include <sys/blah4.h> #include <sys/blah5.h> #include <sys/blah6.h> #include <sys/blah7.h> #include <sys/blah8.h> #include <sys/blah9.h> #include <sys/blah10.h> #include <sys/blah11.h> #include <sys/blah12.h> #include <sys/blah13.h> #include <sys/blah14.h> #include <sys/blah15.h>
请解释一下这为什么不符合您的作业参数?
答案4
尝试这个:
lines=$(grep "#include" tester.c);
test $(echo $lines | wc -l) -ge 3 && {echo $lines | head -n 3} || cat tester.c;
unset lines
注意:此解决方案可以键入一行。我将其分成多行只是为了便于阅读。
编辑
作为对评论的回应,我想您可以将分号替换&&
为
lines=$(grep "#include" tester.c) &&
test $(echo $lines | wc -l) -ge 3 && {echo $lines | head -n 3} || cat tester.c
这在技术上并没有错,但它是lines
固定的。这也是&&
不必要的,但没关系。
此修改后的解决方案仍然具有优点,即您不必像其他一些解决方案那样读取文件两次。
如果您不能使用test
,您可以使用括号,如下所示:
lines=$(grep "#include" tester.c) &&
[ $(echo $lines | wc -l) -ge 3 ] && {echo $lines | head -n 3} || cat tester.c
您甚至可以删除花括号:
lines=$(grep "#include" tester.c) &&
[ $(echo $lines | wc -l) -ge 3 ] && echo $lines | head -n 3 || cat tester.c
这些变体之一应该可以满足您的要求。