连接多个压缩文件,跳过除第一个文件之外的所有文件中的标题行

连接多个压缩文件,跳过除第一个文件之外的所有文件中的标题行

我有一组 gzip 压缩文件,我想将它们组合成一个文件。它们各自具有相同的格式。我想仅保留第一个文件的标头信息,并在后续文件中跳过它。

举一个简单的例子,我有四个相同的文件,其内容如下:

$ gzcat file1.gz
# header
1
2

我想结束

# header
1
2
1
2
1
2
1
2

实际上,我可以拥有不同数量的文件,因此我希望能够以编程方式执行此操作。这是我迄今为止拥有的非编程解决方案......

cat <(gzcat file1.gz) <(tail -q -n +2 <(gzcat file2.gz) <(gzcat file3.gz) <(gzcat file4.gz))

该命令有效,但它是“硬编码”的,可以处理四个文件,我需要将其推广到任意数量的文件。如果有帮助的话,我正在使用bash外壳。我的偏好是性能(实际上文件可能有数百万行长),所以如果速度很快,我可以接受不太优雅的解决方案。

答案1

如果您在问题中显示的命令基本上有效(对于硬编码的文件数量),那么

first=1
for f in file*.gz
do
    if [ "$first" ]
    then
        gzcat "$f"
        first=
    else
        gzcat "$f"| tail -n +2
    fi
done > collection_single_file

应该为你工作。我希望逻辑相当清楚。查看所有文件(根据您的文件名更改通配符)。如果它是列表中的第一个,gzcat那么您将获得整个文件(包括标题)。否则,使用tail剥离标头。处理完一个文件后,其他文件将不再是第一个。

这会调用tail −1 次,而不是一次(就像你的答案)。除此之外,我的答案应该与你的答案相同。

答案2

一个变体G-Man的解决方案不使用单独的变量来跟踪第一个文件:

set -- file*.gz

{
    gzcat "$1"; shift

    for file do
        gzcat "$file" | sed '1d'
    done
} >combined.txt

这将解压缩第一个文件,然后循环遍历其余文件,将每个文件传递给sed删除第一行的简短脚本。输出被重定向到combined.txt.

set -- file*.gz命令将位置参数($1$2等,统称为数组$@)设置为与给定模式匹配的文件名。解压缩后将shift$1从数组中删除。循环遍历数组中剩余的文件名,也可以写成

for file in "$@"; do
    gzcat "$file" | sed '1d'
done

{ ... }允许我们一次性将命令的输出重定向到一个文件。


甚至更短,附加假设“标题行”始终以字符开头#(如问题中的示例),并且数据中没有其他此类行:

gzcat file*.gz | awk 'NR > 1 && /^#/ { next } 1' >combined.txt

或者,

gzcat file*.gz | sed '2,${ /^#/d; }' >combined.txt

#如果它出现在未压缩数据的组合内容的第二行或后面,则这两种方法都会跳过从 开始的任何行。

相关内容