我必须优化一个shell脚本,但是一周之后,我没有成功地对它进行优化。
我必须递归搜索目录中的.c .h和.cpp文件,并检查是否存在这样的字: “float short unsigned continue for signed void default goto sizeof volatile do if static”
words=$(echo $@ | sed 's/ /\\|/g')
files=$(find $dir -name '*.cpp' -o -name '*.c' -o -name '*.h' )
for file in $files; do
(
test=$(grep -woh "$words" "$file" | sort -u | awk '{print}' ORS=' ')
if [ "$test" != "" ] ; then
echo "$(realpath $file) contains : $test"
fi
)&
done
wait
我尝试过使用xargs和-exec,但没有结果,我必须保留这种结果格式:
/ usr / include / c ++ / 6 / bits / stl_set.h包含:if void
的默认值
也许你可以帮助我(优化它)..
编辑:我必须保留每个单词的一个出现 是的:虽然,因为,不稳定...... NOPE:while,for,for,volatile ...
答案 0 :(得分:0)
如果您有兴趣查找至少与您的任何模式匹配的所有文件,可以使用globstar:
shopt -s globstar
oldIFS=$IFS; IFS='|'; patterns="$*"; IFS=$oldIFS # make a | delimited string from arguments
grep -lwE "$patterns" **/*.c **/*.h **/*.cpp # list files with matching patterns
globstar
如果设置,则在文件名扩展上下文中使用模式“**” 将匹配所有文件和零个或多个目录和子目录。 如果模式后跟'/',则只有目录和 子目录匹配。
答案 1 :(得分:0)
这种方法可以保留您想要的格式,同时不使用find和bash循环:
words='float|short|unsigned|continue|for|signed|void|default|goto|sizeof|volatile|do|if|static|while'
grep -rwoE --include '*.[ch]' --include '*.cpp' "$words" path | awk -F: '$1!=last{printf "%s%s: contains %s",r,$1,$2; last=$1; r=ORS; delete a; a[$2]} $1==last && !($2 in a){printf " %s",$2; a[$2]} END{print""}'
grep -rwoE --include '*.[ch]' --include '*.cpp' "$words"
路径
以递归方式搜索以path
开头的目录,仅查找名称与globs *.[ch]
或*.cpp
匹配的文件。
awk -F: '$1!=last{printf "%s%s: contains %s",r,$1,$2; last=$1; r=ORS; delete a; a[$2]} $1==last{printf " %s",$2} END{print""}'
此awk命令重新格式化grep
的输出以匹配您想要的输出。该脚本使用变量last
和数组a
。 last
会跟踪我们所处的文件,a
包含目前为止看到的字词列表。更详细:
-F:
这告诉awk使用:
作为字段分隔符。这样,第一个字段是文件名,第二个字段是找到的字。 (限制:不支持包含:
的文件名。)
' $ 1!= last {printf"%s%s:包含%s",r,$ 1,$ 2;最后= $ 1; R = ORS;删除一个;一个[$ 2]}
每次文件名$1
与变量last
不匹配时,我们都会为新文件启动输出。然后,我们更新last
以包含此新文件的名称。然后,我们删除数组a
,然后将关键$2
分配给新数组a
。
$1==last && !($2 in a){printf " %s",$2; a[$2]}
如果当前文件名与前一个文件名相同且之前没有看到当前单词,我们会打印出找到的新单词。我们还将此词$2
添加为数组a
的关键字。
END{print""}
这将打印出最终换行符(记录分隔符)。
对于那些喜欢将代码分散在多行中的人:
grep -rwoE \
--include '*.[ch]' \
--include '*.cpp' \
"$words" path |
awk -F: '
$1!=last{
printf "%s%s: contains %s",r,$1,$2
last=$1
r=ORS
delete a
a[$2]
}
$1==last && !($2 in a){
printf " %s",$2; a[$2]
}
END{
print""
}'
答案 2 :(得分:0)
您应该可以使用单个grep
命令执行大部分操作:
grep -Rw $dir --include \*.c --include \*.h --include \*.cpp -oe "$words"
这将把它放在文件:word格式中,所以剩下的就是改变它以产生你想要的输出。
echo $output | sed 's/:/ /g' | awk '{print $1 " contains : " $2}'
然后,您可以添加| sort -u
,以便只为每个文件中的每个单词生成一次。
#!/bin/bash
#dir=.
words=$(echo $@ | sed 's/ /\\|/g')
grep -Rw $dir --include \*.c --include \*.h --include \*.cpp -oe "$words" \
| sort -u \
| sed 's/:/ /g' \
| awk '{print $1 " contains : " $2}'