【问题标题】:Concatenate all files in one directory into one file, sorted by modification date, in Bash在 Bash 中将一个目录中的所有文件连接成一个文件,按修改日期排序
【发布时间】:2015-02-16 21:50:02
【问题描述】:

我有成千上万的纯文本格式的作品被移到一个目录中。

在标题中,一些有空格,一些以 - 开头,一些有单/双引号,& 基本上所有其他有效的 Windows 和 Linux 文件名字符都在标题中。

内容文本包含 Windows 和 Linux 行结尾(对 - 这就是它们的名称?)。

在 Linux/Bash 中,我如何将所有这些文件((一半是无扩展名,一半是 .txt))连接到一个文件中,按 修改 日期排序,文件名和文件日期在每个文件的内容之前整齐地打印?

如果可以,请告诉我如何在嵌套文件结构中做同样的事情,这次除了文件名和文件修改日期之外,还为每个文件打印文件路径。

我将不胜感激,这是我多年来自己的写作,我一直在寻找和挣扎几个小时。我是作家而不是程序员 =)

感谢您的考虑。

【问题讨论】:

    标签: linux bash


    【解决方案1】:

    如果你有一些 GNU 好东西和dos2unix:

    find -type f -printf "%T@ %p\0" | sort -nz | while IFS= read -r -d '' l; do f=${l#* }; printf '%s %s\n' "$(date -r "$f")" "$f"; dos2unix < "$f"; echo; done
    

    应该完成这项工作,并且对于您可能拥有的所有有趣的文件名都 100% 安全。递归工作。抱歉,一班长,但现在是就寝时间!


    编辑。 关于你的.fuse_hidden_blahblah 文件:我不知道为什么这个文件在这里,为什么一些内容被递归地添加到自身。我相信您可以通过要求find 明确忽略它来安全地忽略它:

    find \! -name '.fuse_hidden*' -type f -printf "%T@ %p\0" | sort -nz | while IFS= read -r -d '' l; do f=${l#* }; printf '%s %s\n' "$(date -r "$f")" "$f"; dos2unix < "$f"; echo; done
    

    顺便说一下,内容显示在终端屏幕上。如果要将其重定向到文件mycatedfile.txt,则:

    find \! -name 'mycatedfile.txt' \! -name '.fuse_hidden*' -type f -printf "%T@ %p\0" | sort -nz | while IFS= read -r -d '' l; do f=${l#* }; printf '%s %s\n' "$(date -r "$f")" "$f"; dos2unix < "$f"; echo; done > "mycatedfile.txt"
    

    【讨论】:

    • 我做错了吗?它似乎无限循环。
    • 哦 - 它本身就包含了“.fuse_hiddenblabahblahblah”临时文件。就是这样。纠正那个/告诉我我做错了什么&我会给出这个最好的答案。谢谢!
    • @lakitu:我不知道为什么会这样。我已经编辑了帖子以包含一种忽略这些文件的方法。希望这会有所帮助。
    • @gniourf_gnurf:无论出于何种原因,最后一个版本都没有显示给我,但是当我手动将它通过管道传输到文件时(添加“>>/file/path/here/filenamehere. txt”脚本调用后),它工作得很好。我可能只是打错了,我手动复制的。
    • 无论如何我都会授予这个最佳答案
    【解决方案2】:

    使用this 出色的答案(避免parsing ls output 之类的事情)会得到这样的结果(对于单个目录):

    sorthelper=();
    for file in *; do
        # We need something that can easily be sorted.
        # Here, we use "<date><filename>".
        # Note that this works with any special characters in filenames
    
        sorthelper+=("$(stat -n -f "%Sm%N" -t "%Y%m%d%H%M%S" -- "$file")"); # Mac OS X only
        # or
        sorthelper+=("$(stat --printf "%Y    %n" -- "$file")"); # Linux only
    done;
    
    sorted=();
    while read -d $'\0' elem; do
        # this strips away the first 14 characters (<date>) 
        sorted+=("${elem:14}");
    done < <(printf '%s\0' "${sorthelper[@]}" | sort -z)
    
    for file in "${sorted[@]}"; do
        if [ -f "$file" ]; then
            echo "$file";
            cat "$file";
        fi
    done; > Output.txt
    

    对于嵌套层次结构,在支持它的 shell 中使用 for file in **; do(我知道的 bash 版本 4+ 和 zsh)或将上述内容放入一个函数中并在循环中的目录上递归调用它(完全在下面的代码未经测试)。

    catall() {
        declare sorthelper=();
        for file in *; do
            # We need something that can easily be sorted.
            # Here, we use "<date><filename>".
            # Note that this works with any special characters in filenames
    
            sorthelper+=("$(stat -n -f "%Sm%N" -t "%Y%m%d%H%M%S" -- "$file")"); # Mac OS X only
            # or
            sorthelper+=("$(stat --printf "%Y    %n" -- "$file")"); # Linux only
        done;
    
        declare sorted=();
        while read -d $'\0' elem; do
            # this strips away the first 14 characters (<date>) 
            sorted+=("${elem:14}");
        done < <(printf '%s\0' "${sorthelper[@]}" | sort -z)
    
        for file in "${sorted[@]}"; do
            if [ -f "$file" ]; then
                echo "$file";
                cat "$file";
            elif [ -d "$file" ]; then
                catall "$file"
            fi
        done;
    }
    
    $ catall > Output.txt
    

    编辑:正如在 gniourf_gniourf 的出色回答中所注意到的那样,我没有考虑到输入文件中不同的行结尾。在上面使用 dos2unix &lt;"$file" 而不是 cat "$file" 应该按照指示进行规范化。

    再次编辑:嗯...只是注意到这不包括输出中的修改时间。将其输入输出的最简单方法也是最昂贵的(在输出时再次获取),但像 gniourf_gniourf 的答案中所采用的解决方案也可以在这里工作(将sorthelper 放到sorted 循环并使用最后循环中的时间戳以将其写入文件)。

    【讨论】:

    • 你们太棒了,让我把这个放到我的(离线)写作电脑上。非常感谢,在我给出一个确认的工作“最佳答案”之前会有点。
    • 嘿 Etan - 我复制了这个,但我得到 'stat: invalid option -- 'n'' 作为循环中的错误(它反复重复) - 如果我的stat 没有 -n 作为选项?
    • (我刚刚检查过,我有 8.21 版的统计数据,如果有帮助的话)
    • 看看这两行的 cmets。它们是备用的stat 呼叫选择。
    • 感谢 Reisner 先生的努力。不胜感激。
    猜你喜欢
    • 2017-08-16
    • 1970-01-01
    • 1970-01-01
    • 2020-12-08
    • 1970-01-01
    • 2015-02-13
    • 1970-01-01
    • 1970-01-01
    • 2015-05-03
    相关资源
    最近更新 更多