
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
シェルを使っています。私が好むのはパフォーマンスです(実際にはファイルの長さは数百万行に達することができます)。したがって、速度が速い場合は、あまりエレガントな解決策も問題ありません。
答え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回ではなく-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
#
圧縮されていないデータの組み合わせで2行目以降に表示される場合、両方の方法が最初からすべての行をスキップします。