中間ファイルなしで複数のコマンドの結果を別のコマンドにリンクしてパイプする方法は?

中間ファイルなしで複数のコマンドの結果を別のコマンドにリンクしてパイプする方法は?

xzで圧縮された4つの非常に大きなテキストファイルがあるとしましょう。

file1.log.xz
file2.log.xz
file3.log.xz
file4.log.xz

私がしたいことは接続です。圧縮されていないこの4つのファイルの内容を新しいファイルにマージしますfile.xz。問題は、理想的には中間ファイルをチェックする必要がないことです。

これらのファイルは、サイズがギガバイト単位で測定される非常に大きなログファイルです。圧縮すると100 MB未満ですが、4つのファイルをすべて展開して再接続するには、圧縮されていないファイルには少なくとも30 GBの記憶領域が必要です。もちろん、cat圧縮されていないすべてのファイルをxz再圧縮することもできます。

cat file1.log file2.log file3.log file4.log | xz -ve9 - > newfile.log.xz

私はどのように接続するのか知っています二つあるファイルは解凍され、もう一方は圧縮されたと仮定し、コマンドラインで中間ファイルなしでファイルを表示します。

xz -d -c file2.log.xz | cat file1.log - | xz -ve9 - > files1and2.log.xz

ただし、この方法は1つのファイルでのみ機能し、ファイルの1つを解凍する必要があります。

さまざまな.xzファイルをまとめることができるかどうかはわかりませんcat。異なるパラメータを使用して圧縮されている可能性があるとします。

高いレベルでは、次の質問を投げることができます。複数(3つ以上)コマンドの出力を取得してこれらの出力をリンクし、中間ファイルなしで別のプロセスにパイプすることはできますか? (仮説のシナリオ:私が何かをしていると想像してください。処理4つの非常に大きなファイルすべてに対してstdoutとして出力し、出力を別の圧縮ファイルに保存したいスクリプトを使用します。 )

シェルコマンドのみを使用してこれを実行できますか?

答え1

文書xzによると

.xzファイルはそのまま接続できます。xzこれらのファイルは単一のファイルであるかのように解凍されます.xz

私のテストでは、他のファイルが別のオプションに圧縮されていても機能します。

cat -- *.log.xz > newfile.log.xz

うまくいくでしょう。

より一般的な質問に答えるには、複合コマンドの出力をパイプするだけです。例えば

for file in -- *.log.xz; do xzcat -- "$file"; done | xz -ve9 > newfile.log.xz

またはサブシェル。これにより、ログファイルを再圧縮する前に必要な処理を実行できます。ただし、デフォルトの場合は、以下を実行してすべてのファイルを解凍して再圧縮することができます。

xzcat -- *.log.xz | xz -ve9 > newfile.log.xz

追加すると、-f圧縮されていないファイルにも機能します。

xzcat -f -- uncompressed.log *.log.xz | xz -ve9 > newfile.log.xz

圧縮されていないログと圧縮されたログをマージできます。

答え2

努力する

for x in *.log.xz
do
  xz -d -c "$x"
done | xz -ve9 - > newfile.log.xz

(もちろんオンラインでも可能です。)

圧縮されていない新しいファイルを追加するには、サブシェル(())を使用します。

( cat newfile.log 
for x in *.log.xz
do
  xz -d -c "$x"
done ) | xz -ve9 - > newfile.log.xz

答え3

xzcat -fあなたの質問の最初の部分への答えです。しかし、あなたは正しいです。cat *xz | xzcatいくつかのファイルが-F lzma

より高いレベルでは、次の質問自体を行うことができます。複数(3つ以上)コマンドの出力を取得してこれらの出力をリンクし、中間ファイルなしで別のプロセスにパイプすることはできますか?

ここで問題は、中間出力をファイルに保存しない場合です。する保存しますか?

RAMに保存される場合は、使用可能なRAM容量によって制限されます。この値を超えると、コンピュータはすぐに地獄に行きます。

tmpfsGNU Parallelはそれを一時ファイルに保存しますが、ファイルシステムに入れるとデフォルトでRAMに保存されます。

mkdir mytmp    
sudo mount tmpfs mytmp -t tmpfs -o rw,size=3P
parallel --tmpdir mytmp seq {}00000000 {}99999999 ::: 1 2 | grep 0000000

ただし、出力を1行ずつ混合できる場合は、実行中のプログラムごとにRAMに1行だけ保存できます。

GNU Parallel(>バージョン20170822)が実行する操作は次のとおりです。

parallel --lb seq {}00000000 {}99999999 ::: 1 2 | grep 0000000

3番目の回避策は、高速コンプレッサーを使用して一時ファイル(たとえば、、、などpzstdpigzlz4圧縮lzopすることです。

parallel --compress seq {}00000000 {}99999999 ::: 1 2 | grep 0000000

(GNU Parallelはインストールされた高速圧縮機を自動的に検出します)。

答え4

@Archemarがこの問題について話しましたが、実際にタイトルの質問に直接答えた人はいないようです。

中間ファイルなしで複数のコマンドの結果を別のコマンドにリンクしてパイプする方法は?

そして投稿でこれを繰り返します。

より高いレベルでは、次の質問自体を行うことができます。複数(3つ以上)コマンドの出力を取得してこれらの出力をリンクし、中間ファイルなしで別のプロセスにパイプすることはできますか?

Archemarが提案したように、要求されたアクションを実行する一般的な方法はサブシェルを使用することです。

バッシュ構文:

(
  command_one
  command_two
  command_three
...
  command_N
) | next_command

関連情報