如何处理固定数量的未知文件?

时间:2019-06-06 05:28:50

标签: bash

我正在一个小型项目中,我以这种方式显示了压缩日志:

youyou.log
youyou.log.1.gz
youyou.log.2.gz
youyou.log.3.gz

我必须解压缩它们的位置,然后将它们从最高索引合并到youyou.log

问题是,有时我可能只有一个文件,有时甚至更多,但是未知它可能会持续到youyou.log.n.gz

我开始写一些可以工作的东西,但是一点都不优雅。 我假设有一定数量的.gz文件,但给出了一些错误,稍后我会忽略。

main.sh    
#!/bin/bash

gunzip *.gz 
cat youyou.log.7 youyou.log.6 youyou.log.5 youyou.log.4 youyou.log.3 .log.2 youyou.log.1 youyou.log > youyou_complete.log 

然后像这样忽略:

 main.sh  > /dev/null 2>&1

请问有更好的方法来解决这个问题吗?谢谢

4 个答案:

答案 0 :(得分:1)

请尝试以下操作:

find . -name "youyou.log.*.gz" -maxdepth 1 | sort -rn -t. -k4 | xargs zcat | cat - youyou.log > youyou_complete.log

它假定您没有提前解压缩*.gz文件。

[说明]

  • find . -name "youyou.log.*.gz" -maxdepth 1查找具有指定名称的文件 当前目录中的模式,然后创建一个列表,例如:

    ./youyou.log.1.gz
    ./youyou.log.2.gz
    ./youyou.log.3.gz
    [snip]
    ./youyou.log.9.gz
    ./youyou.log.10.gz
    
  • sort -rn -t. -k4首先将传递的文件名分隔在“。”上, 那么内部列表将类似于:

    (null)  /youyou  log  1  gz
    (null)  /youyou  log  2  gz
    (null)  /youyou  log  3  gz
    [snip]
    (null)  /youyou  log  9  gz
    (null)  /youyou  log  10 gz
    
  • -k4选项告诉sort将文件名列表按第4位排序 列(1、2、3,..)。 -n选项指定数字排序 和-r选项使比较结果相反。

  • 现在,关注列表已发送到xargs命令的标准输入:

    ./youyou.log.10.gz
    ./youyou.log.9.gz
    [snip]
    ./youyou.log.3.gz
    ./youyou.log.2.gz
    ./youyou.log.1.gz
    
  • xargs创建一个命令,该命令由以下参数组成 通过从标准输入中读取的参数。 然后该命令将如下所示:

    zcat ./youyou.log.10.gz ./youyou.log.9.gz ... ./youyou.log.1.gz 
    
  • zcat解压缩文件列表并写入未压缩的数据 通过按参数顺序合并数据来实现标准输出。

  • 最终命令cat - youyou.log连接标准输入,并且 然后按指定顺序youyou.log将结果重定向到 youyou_complete.log

如果您的sort支持-z选项,最好这样说:

find . -name "youyou.log.*.gz" -maxdepth 1 -print0 | sort -z -rn -t. -k4 | xargs -0 zcat | cat - youyou.log > youyou_complete.log
  • -print0选项告诉find使用空字符\0作为分隔符 文件名列表而不是换行符。 -z的{​​{1}}选项和 sort的{​​{1}}选项与之合作。
    如果文件名包含空格或换行符, -0错误地将参数列表拆分给它们。这可能不 在给定的示例中发生,因为文件名显然没有 包含空格,但是这种考虑可能有用 使脚本更加安全和面向未来(IMHO)。

答案 1 :(得分:0)

以下是使用Python的示例

import os
path = "/home/user/logs/"
listOfFiles = os.listdir(path)
mainFile = open("youyou.log.complete", "a")
for file in listOfFiles:
    os.system("gunzip ", file)
listOfUnzipped = os.listdir(path)
for file in listOfUnzipped:
    secondaryFile = open(file, "r")
    text = secondaryFile.read()
    mainFile.write(text)
    mainFile.write("\r\n")
    secondaryFile.close()
mainFile.close()

答案 2 :(得分:0)

touch tmp.log
gzip -c tmp.log > tmp.log.gz

for i in $(dir -r *.gz); do
  cat $i >> tmp.log.gz
done

gunzip tmp.gz

cat youyou.log >> tmp.log

我还没有测试它,虽然代码可以自我解释。

我唯一担心的是,如果您有名称为.gz等的日志文件,则dir的输出youyou.log.11, youyou.log.22的文件顺序。

答案 3 :(得分:0)

棘手的部分是按降序获取文件,您的说明还不清楚,这是什么意思。例如,如果您有youyou.log.32和youyou.log.4-应该先哪个?如果您对严格的字符顺序感兴趣,可以使用ls来获得适当排序的列表(具有ls的所有陷阱),即

# bash
cat $(ls -r youyou.log.[0-9]*) >youyou.complete.log

或者您可以从bash切换到zsh,在其中可以通过排序完成文件名的生成。 示例:

# zsh
cat youyou.log.[0-9]*(On) >youyou.complete.log

(On)的名称降序排列。这将在youyou.log.4之后对youyou.log.32进行排序。如果您可以安排日志文件具有适当的时间戳记,则使用(Om)而不是(On)将对修改时间进行降序排序。

如果您没有时间戳,但是想对文件进行“数字”排序,即youyou.log.32比youyou.log.4早,因为4小于32,这是我能想到的最佳解决方案将使用sort

# bash
cat $(echo youyou.log.[0-9]*|fmt -w 1|sort -n -r -t. -k 3) >youyou.complete.log

fmt确保每行有一个 youyou 文件,而sort在第三个字段(-k 3)上按数字(-n)排序,其中字段分隔符是句点(-t。)。