Bash:在其他文件中查找对文件名的引用

时间:2013-05-24 20:02:02

标签: bash grep

问题:
我有一个文件名列表,filenames.txt: 例如

/usr/share/important-library.c
/usr/share/youneedthis-header.h 
/lib/delete/this-at-your-peril.c

我需要重命名或删除这些文件,我需要在项目目录树中找到对这些文件的引用:/home/noob/my-project/所以我可以删除或更正它们。

我的想法是使用bash提取文件名:basename filename,然后使用for循环在项目目录中grep它。

FILELISTING=listing.txt
PROJECTDIR=/home/noob/my-project/

for f in $(cat "$FILELISTING"); do
    extension=$(basename ${f##*.})
    filename=$(basename ${f%.*})
    pattern="$filename"\\."$extension"
    grep -r "$pattern" "$PROJECTDIR"
done

我可以搞砸这个项目 - 有没有人看到我逻辑上的缺陷;更好:你是否看到一个更可靠的可扩展方式来在一个巨大的目录树上执行此操作?让我们假设版本控制不在桌面上(事实上)。

2 个答案:

答案 0 :(得分:5)

一些评论:

  • 而不是

    for f in $(cat "$FILELISTING") ; do
        ...
    done
    

    编写

    更安全一些
    while IFS= read -r f ; do
        ...
    done < "$FILELISTING"
    

    这样,您的代码对文件名中的空格,制表符,星号等没有任何问题(尽管它仍然不支持换行符)。

  • 您将f分隔为extensionfilename,然后使用\.重新组合它们的目标,似乎是您希望对待文件名作为文字串;对?比如,你担心grep会将.视为“任何角色”,而不是“一个点”。更通用的解决方案是使用grep的{​​{1}}选项,它告诉它将模式视为固定字符串而不是正则表达式:

    -F
  • 您的介绍使用grep -r -F "$f" "$PROJECTDIR" 提及,但之后您实际上并未使用它。这是故意的吗?

  • 如果您故意不使用basename,那么basename实际上只包含要搜索的模式列表;在这种情况下,您甚至不需要编写循环,因为filenames.txt的{​​{1}}选项告诉它从文件中获取换行符分隔的模式列表:

    grep

  • 您应该使用-f之类的内容备份项目。 “修订控制不在考虑范围内”并不意味着您无法实现回滚策略!

已编辑添加:

  • 要立即将所有基本名称传递给grep -r -F -f "$FILELISTING" "$PROJECTDIR" ,希望它可以更聪明地使用它们,而不仅仅是循环遍历它们,就像呼叫是分开的一样,你可以写一些东西像:

    tar -czf backup.tar.gz "$PROJECTDIR"

    (为了简洁起见,我使用了grep而不是grep -r -F "$(sed 's#.*/##g' "$FILELISTING")" "$PROJECTDIR" + sed,但如果您愿意,可以在while内完整循环。)

答案 1 :(得分:1)

这是IDE的工作。

你是对的,这是一项危险的任务,除非你知道构建过程和搜索目录以及目录的顺序,否则你真的不能说出哪个标题与哪个文件有关。

让我们采取一些简单的事情:

# include "sql.h"

项目headers/sql.h中有一个文件。该文件需要吗?也许是。也许不吧。还有/usr/include/sql.h。也许这就是实际使用的那个。如果不查看Makefile并查看 include 目录的顺序,你就无法分辨。

然后,有包含的库,可能需要自己的头文件才能编译。而且,一旦你进入C预处理器,你真的会很难。

这是IDE(集成开发环境)的任务。 IDE构建项目并跟踪文件和其他资源依赖性。在Java世界中,大多数人使用Eclipse,并且为这些开发人员提供了一个C / C ++插件。但是,有over 2 dozen listed in Wikipedia,几乎所有这些都是开源的。最好的将取决于您的环境。