Bash:如何控制迭代流/循环?

时间:2013-03-10 20:41:53

标签: bash file recursion iteration

为了查看一些恢复的数据,我正在编写一个递归遍历文件夹和文件的脚本。文件,最后在它们上运行文件,以检查它们是否可能从某个备份中完全恢复。 (恢复的文件播放,并被识别为mp3或其他音频,非工作文件为ASCII文本)

现在我只是满意于让它超越我的测试文件夹结构,打印所有文件夹&相应的文件。 (打印它们主要用于测试,但也因为我想记录脚本当前所在的位置以及它到底有多远,以验证已处理的内容)

我尝试使用2 for循环,一个用于文件夹,然后一个用于文件。 (理想情况下,它需要1个文件夹,然后列出那里的文件(或可能深入研究子文件夹),每个文件夹下面只提供该子文件夹中的文件,然后继续下一个文件夹。 如:

Folder1  
- File 1  
- File 2  
    -- Subfolder  
    -- File3  
    -- File4  
Folder2  
- File5  

然而,这似乎并不适用于通常提出的方式(例如for循环)。我为目录使用“find.-type d”并且“find。-type f”或“find * -type f”(因此它不会进入子目录)但是,当只是打印时路径/文件,以检查它是否按我的意愿运行,很明显,这不起作用。

似乎总是首先打印所有目录(第一个循环)然后打印所有文件(第二个循环)。为了跟踪它正在做什么以及为了更容易知道检查/恢复的内容,我希望以更有序的方式执行此操作,如上所述。 那么我只是做错了什么,或者这可能是bash中for循环的一般限制?

另一个可能相关的问题:尽管将find的输出分配给数组似乎有效,但它无法作为数组访问...

  

循环示例:
     对于'$(find.-type d)'中的文件夹;做
             echo $文件夹
             让foldercounter ++
     完成了

     

阵列:      folders =(“$(find。-type d)”)
     #据我所知,这应该将输出分配为数组
     #但是,它并没有真正以某种方式正确分配为      echo“$ folders [1]”
     #不起作用(空格必需的引号)

2 个答案:

答案 0 :(得分:1)

  

为了查看一些恢复的数据,我正在编写一个递归遍历文件夹和文件的脚本。文件,最后在它们上运行文件,以检查它们是否可能从某个备份中完全恢复。 (恢复的文件播放,并被识别为mp3或其他音频,非工作文件为ASCII文本)

如果要在当前目录中的每个文件和目录(包括其子目录等)上运行file,则不需要使用Bash for - 循环,因为您可以只需告诉find运行file

find -exec file '{}' ';'

-exec ... ';'选项在每个匹配的文件或目录上运行命令...,将参数{}替换为文件的路径。)

如果您只想在常规文件(而非目录)上运行file,则可以指定-type f

find -type f -exec file '{}' ';'

如果您(比如)想要打印目录名称,但在常规文件上运行上述内容,则可以使用-or运算符连接一个使用-type d的指令和一个使用该指令的指令-type f

find -type d -print -or -type f -exec file '{}' ';'

编辑添加:如果需要,可以通过编写递归shell函数,在纯Bash(当然还有file命令)中实现上述命令的效果。例如:

function foo () {
    local file
    for file in "$1"/* ; do
        if [[ -d "$file" ]] ; then
            echo "$file"
            foo "$file"
        else
            file "$file"
        fi
    done
}
foo .

这与find命令的不同之处在于它会更加一致地对文件进行排序,也许在细节处理点文件和符号链接等细节上,但大致相同,因此可以用作进一步调整的起点。

答案 1 :(得分:1)

一个find ... -exec ...解决方案@ H.-Dirk Schmitt指的可能看起来像:

find . -type f -exec sh -c '
    case $(file "$1") in
    *Audio file*)
        echo "$1 is an audio file"
        ;;
    *ASCII text*)
        echo "$1 is an ascii text file"
        ;;
    esac
' _ {} ';'