我尝试 grep 一些字符串,并希望 grep 在“+”符号处停止。搜索的字符串可能是“foo”或“foo+bar”。无论 foo 后面是什么,Grep 都会处理所有结果,并且 -w 选项似乎也将“+”识别为整个单词。因此,我想 grep 所有包含“foo”匹配项的文件,但不处理“foo+bar”之类的匹配项。该命令应存储在这样的变量中
COUNT="$(find . -maxdepth 1 -type f -name '*.sh' | xargs grep -w -o -m 1 "foo" | wc -l)"
那么,如何修改这个变量才能只找到文件中的 foo 条目而不是 foo + bar。
编辑:我终于找到了适合我的情况的解决方案。也许我没有清楚地描述我需要什么,但诀窍是在搜索字符串的开头添加 ^ 并在结尾添加 $。因此,文件夹中可能包含 text=foo 或 text=foo+bar 之类的文件应该被过滤,因此当我搜索 text=foo 时,grep 只会输出这些,而不包括 text=foo+bar。我的代码现在看起来像
COUNT="$(find . -maxdepth 1 -type f -name '*.sh' | xargs grep -x -o -m 1 "^text=foo$" | wc -l)"
现在在这种情况下 grep 不会计算 text=foo+bar 的结果。听起来很简单,但我又费了一番功夫才弄清楚 :)
答案1
如果你想匹配并计算(文件名), 然后 ...
grep
您可能根本不需要这样的任务...您可以使用find
s来包含和排除文件名模式-name "..."
来包含和! -name "..."
排除...您可以根据需要嵌套任意数量的文件名模式以仅匹配您想要的文件名,例如像这样:
find -type f -name "*foo*.sh" ! -name "*+*.sh"
这将输出名称中.sh
带有foo
和不带有扩展名的文件。+
因此你的命令替换设置参数(注意:shell 的内置命令全部使用大写字母...因此,请使用小写字母或大小写混合字母作为参数) 将会:
count=$(find -maxdepth 1 -type f -name "*foo*.sh" ! -name "*+*.sh" | wc -l)
注意.
(当前工作目录) 是find
默认搜索路径...所以您不必指定它。
如果你想匹配并计算(每个文件内的文本), 然后 ...
grep
您可能根本不需要这些...但是,除了完成相当复杂的任务之外,您可能需要一个更为复杂的工具...您只能使用awk
shell 的文件名通配符,如下所示:
awk '{for ( i=1; i <= NF; i++ ) { if ( $i !~ "+" ) { if ( $i == "foo" ) { count++ }} else { nextfile }}} END { print count }' *.sh
for ( i=1; i <= NF; i++ )
将传递每个单个字段(“单词”)在当前行自行进入下一个操作,其中if ( $i !~ "+" )
将检查字段没有包含+
字符(例如该字段是不是 +
,foo+bar
,+foo
或者foo+
)如果为真,则将其传递给下一个操作,该操作if ( $i == "foo" )
将检查该字段是否准确foo
,如果为真,则使用增加计数器count++
,否则else
它将退出当前文件并继续处理下一个文件(传递给awk
文件/参数)使用nextfile
和将END
打印当前计数器的值(所有已处理文件的总数) 使用print count
。
并且您的命令替换设置参数(使用printf
而不是print
避免在参数中注入换行符) 将会:
count=$(awk '{for ( i=1; i <= NF; i++ ) { if ( $i !~ "+" ) { if ( $i == "foo" ) { count++ }} else { nextfile }}} END { printf "%d", count }' *.sh)
即使在数千个文件上运行它,它也应该正常工作...但是,如果您的文件数以万计或更多,并且您收到Argument list too long
错误消息,那么,恕我直言,您需要重新考虑在您的脚本中完全包含这样的任务,并找到实现您的目标的不同方法。