我正在尝试编写一个bash
脚本来搜索指定目录树中的文件内容是否存在指定的子字符串。
仅使用grep
的递归函数是不够的,因为我可能需要遍历/
系统的目录(和所有子目录),这会grep
导致内存不足并中止。因此,我决定使用以下变量来获取指定目录树中所有目录和子目录的列表,这些find
变量表示传递给脚本的参数。
searchdir=$HOME # passed in a script argument
searchstr="secret" # passed in a script argument
我调用该find
实用程序并将输出存储到一个临时文件中。
TF=$(mktemp)
find ${searchdir} -type d 1>$TF 2>/dev/null
使用临时文件中所有目录的列表,我继续使用循环遍历该文件的行,while-do
以对每个目录中的所有文件执行搜索。对于grep
,我使用此答案中提供的参数格式来搜索单个目录中的所有文件,包括隐藏文件。
cat $TF | while read line || [[ -n $line ]];
do
grepdir="${line}/{*,.*}"
grep -sHn "${searchstr}" ${grepdir}
done
...但是,该代码不会产生任何输出。
我验证了...
${TF}
确实包含所有目录的正确列表。输出${grepdir}
变量给出了我期望找到的输出。
/home/user/{*,.*}
/home/user/.ssh/{*,.*}
/home/user/test/{*,.*}
# ... and so on
如果我grep
使用硬编码目录运行命令,特别是该~/test/
目录,该目录包含两个测试文件,其中包含它应该找到的字符串
grep -sHn "${searchstr}" /home/user/test/{*,.*}
...它正确输出包含子字符串“secret”的两个文件。
/home/user/test/asdf:7:secret
/home/user/test/test.txt:5:asdfasfdsecretaasdfafd
一种对我有用的格式是在讨论递归使用的答案grep
中最初提到的格式。如果我这样做:
cat $TF | while read line || [[ -n $line ]];
do
grep -rn "${line}" -e "${searchstr}"
done
...我得到了一些输出(技术上是正确的,但是有很多重复的条目),但是由于grep
递归地处理目录并且我有一个所有目录的列表,我一定会在目录上多次得到相同的结果,例如前面提到的根目录grep
将完全失败,这是我试图避免的。
我可能还应该提到,我为了让它工作而拼命的破解,比如作为$(echo "${grepdir}")
参数传递,也没有导致任何结果。
我的想法或理解很可能存在误解bash
。在调用之前不应该bash
扩展变量吗?我的脚本哪里出错了?${grepdir}
grep
规则 #1:当命令或脚本没有按照您 的意愿执行时,请查看错误消息。 不要把它们扔进
/dev/null
.您收到错误消息,例如
但你没有看到它们。
如果我们查看bash(1),我们会看到
您的情况的重要部分是大括号扩展发生在变量扩展之前。所以,如果你说
然后
"${line}"/*
and"${line}"/.*
,/home/user/*
and/home/user/.*
,然后但是,当你说
然后
/home/user/{*,.*}
,然后大括号扩展发生为时已晚。
grep
查找名为字面意思的文件/home/user/{*,.*}
。附言
也不起作用,因为引号会阻止大括号扩展和路径名扩展的发生。
PPS 你不需要所有的牙套;
会好的。
grep 在整个系统上递归时中止的原因可能不是它无法处理数据量,而是它在 /proc、/sys 或 /dev 中的一个或另一个伪文件或设备文件上跳闸。
--exclude
您可以使用命令行上的选项排除有问题的目录。它不扩展通配符的原因是因为它们在这一行中被引用:
将其更改为此可能会帮助他们扩展。
实现此目的的另一种方法(代表您使用较少的脚本)是使用文件路径选择文件
find
并将文件路径传送到以xargs
进行处理:find / ... -print 0 | xargs -0 ...
但是,任何一种方式都可能仍然会绊倒原始递归 grep 绊倒的任何文件,除非您将它们排除在外。