grep 没有为变量中传递的目录提供输出

grep 没有为变量中传递的目录提供输出

我正在尝试编写一个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

规则#1:当命令或脚本没有按照您的意愿执行时, 查看错误消息。  不要把它们扔进 /dev/null.

您收到类似错误消息

grep: /home/user/{*,.*}: No such file or directory
grep: /home/user/.ssh/{*,.*}: No such file or directory
grep: /home/user/test/{*,.*}: No such file or directory

但你没有看到他们。

如果我们看一下重击(1), 我们看

扩展是在命令行上被分割成单词后执行的。执行的扩展有七种:大括号扩展、波形符扩展、参数和变量扩展、命令替换、算术扩展、分词和路径名扩展。

展开的顺序是:大括号展开;波形符扩展、参数和变量扩展、算术扩展和命令替换(以从左到右的方式完成);分词;和路径名扩展。

对于您的情况来说,重要的部分是大括号扩展发生在变量扩展之前。所以,如果你说

grep -sHn "${searchstr}" "${line}"/{*,.*}

然后

  • 大括号扩展会将最后一个标记变成"${line}"/*and "${line}"/.*
  • 变量扩展会将上面的内容变成/home/user/*and /home/user/.*,然后
  • 路径名扩展会将上面的内容转换为文件名列表。

但是,当你说

grep -sHn "${searchstr}" ${grepdir}

然后

  • 变量扩展将最后一个标记变成/home/user/{*,.*},

然后大括号扩展发生就为时已晚。  grep查找名为literal 的文件/home/user/{*,.*}


聚苯乙烯

grep -sHn "${searchstr}" "${line}/{*,.*}"

也不起作用,因为引号会阻止大括号扩展和路径名扩展的发生。

PPS:你不需要那么多牙套;

grep -sHn "$searchstr" "$line"/{*,.*}

就可以了。

答案2

grep 在整个系统上递归时中止的原因可能不是它无法处理大量数据,而是它在 /proc、/sys 或 /dev 中的一个或另一个伪文件或设备文件上出错。您可以使用--exclude命令行上的选项排除有问题的目录。

它不扩展通配符的原因是因为它们在这一行中被引用:

    grepdir="${line}/{*,.*}"

将其更改为这一点可能会有助于它们的扩展。

    grepdir="${line}/"{*,.*}

实现此目的的另一种方法(代表您编写较少的脚本)是使用文件路径来选择文件find并将文件路径传递到xargs进行处理:find / ... -print 0 | xargs -0 ...

然而,无论哪种方式都可能仍然会绊倒原始递归 grep 绊倒的任何文件,除非您排除它们。

相关内容