1つのファイルに結合したいgzip圧縮されたファイルのコレクションがあります。それらはそれぞれ同じ形式です。最初のファイルのヘッダー情報のみを保持し、後続のファイルではスキップしたい。
簡単な例として、次の内容の4つの同一のファイルがあります。
$ 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))
このコマンドは機能しますが、4つのファイルを処理するように「ハードコード」されているため、任意の数のファイルに対して一般化する必要があります。それが助けになるなら、私はシェルとしてbash
を使用しています。私の好みはパフォーマンスです(実際にはファイルは数百万行の長さになる可能性があります)ので、高速であればエレガントではないソリューションで問題ありません。
質問に表示するコマンドが基本的に機能する場合(ハードコードされた数のファイルに対して)、
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
を使用してヘッダーを削除します。ファイルを処理した後は、他のファイルが最初になることはありません。
これにより、(回答のように)1回だけではなく、tail
[〜#〜] n [〜#〜]-1回呼び出されます。それを除けば、私の答えはあなたの答えと同じように機能するはずです。
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
これらは両方とも、圧縮されていないデータの結合されたコンテンツの2行目以降にある場合、#
で始まる行をスキップします。