在bash脚本中实现find的简单版本

时间:2015-02-25 04:22:44

标签: linux bash shell

我的作业要求我创建一个find版本,可以使用以下参数:

  1. -name(处理名称的模式)
  2. -type(f和d)
  3. -print
  4. -exec(能够处理{},虽然如果exec存在,您可以假设它始终是最后一个参数,不需要用分号终止
  5. 它还指出"谓词可以按任何顺序出现,并且隐式短路AND。不要处理-o(OR)。"我也不允许在我的剧本中使用find

    因此,示例输入将如下所示:

    myfind ~/dirtocheck/ -name '*.o' -type f -print -exec /bin/mv {} ~/.TRASH\;
    

    关于如何完成所有这些,我有几个问题。

    首先,我想知道如何使用递归来导航路径。这是我的函数的伪代码版本:

    recurse_path () {
        for i in "$@"; do
            # call a function that executes rest of program
            if [[ -d "${i}" ]]; then
                cd "${i}"
                recurse_path $(ls ".")
            fi
        done
    }
    

    其次,我不知道将传递多少参数或者真正如何正确解析它们。在执行任何可以使这更容易的事情之前,我应该做些什么吗?

    例如,我假设我们有一个'-exec'参数,我可以接受任何事情,并将其移动到一个数组中执行。但是我该怎么做呢?

    最后,它是什么意思"谓词可以以任何顺序出现,并且隐含地短路并联在一起。"我假设这意味着下一个要执行的每一件事都必须是真的,但我不知道为什么它们会出现故障?

    我会很感激任何帮助,甚至是如何构建它以使其发挥作用的想法。

2 个答案:

答案 0 :(得分:3)

  

首先,我想知道如何使用递归来沿着路径导航。

您的代码是一个良好的开端。为了表现得像find,我会删除对cd的调用,而是始终使用相对于起始目录的路径。这意味着递归越深,它们就越长。

同样recurse_path $(ls ".")是一种编写recurse_path *的复杂方式。

  

其次,我不知道将传递多少个参数或者真正如何正确解析它们。

作为提示,您可以编写一个循环来检查每次迭代$1,然后使用shift在处理完参数后删除它们,以便$1指向下一组论点。例如,如果$1-name,请在$2中处理该名称,然后调用shift 2

  

例如,我假设我们有一个'-exec'参数,我可以接受任何过去,并将其移动到一个数组中执行。但是我该怎么做呢?

如果您使用基于shift的方法,则-exec的参数自然可以简单地作为"$@"访问。

  

最后,它是什么意思“谓词可以以任何顺序出现,并且隐含地短路并联在一起。”我假设这意味着每一件事都必须是真的,以便下一个执行,但我不知道他们为什么会出现故障?

您不能认为-name出现在-type之前。它们可能处于任何一种顺序,或者它们可能会丢失,甚至可能重复多次。例如:

myfind ~/dirtocheck/ -name '*.o' -type f
myfind ~/dirtocheck/ -type f -name '*.o'
myfind ~/dirtocheck/ -name 'MyClass*' -name '*.java'

答案 1 :(得分:1)

首先:你的递归看起来很好。我唯一需要注意的是ls确实不应该以这种方式使用,因为格式化输出。您需要直接使用shell-glob扩展:recurse_path *。 (请注意,再见默认情况下,这不会包含以.开头的任何内容。您的作业是否解决了如何处理“隐藏”文件的问题?我认为,find正常对待它们,这意味着您可能需要打开Bash的dotglob选项。

(另请注意,JohnKugelman的回答提出了关于完整路径的一个好处。尽管使用cd仍然可以工作 - 例如,你可以在变量中维护相对路径。虽然没有真正的原因使用cd。)

第二:你几乎肯定会使用shift来获取你的论点。请注意,这会更改您的位置参数变量($1$2等)以及列表变量($*$@)。因此,举例来说,如果您注意到$1(在shift s之后)为-exec,那么您可以再次shift$@将包含要执行的命令(modulo替换{}等)。

第三:是的,短路and意味着如果不满足条件,则不评估/测试下一个条件;您可能会发现阅读有关短路操作符很有帮助,但这个概念很简单,听起来您可能已经理解了它。我相信“任何订单”条款意味着您可以-type-name之前。{/ p>