Come concatenare i risultati di più comandi e reindirizzare in un altro senza file intermedio?


1

Supponiamo che io abbia quattro file di testo molto grandi, tutti compressi con xz.

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

Quello che mi piacerebbe fare è concatenare i contenuti non compressi di questi quattro file in un nuovo file file.xz. Il fatto è che vorrei idealmente non dover passare attraverso i file intermedi.

I file sono file di registro molto grandi di dimensioni gigabyte. Compresso, sono inferiori a 100 MB, ma se dovessi espandere tutti e quattro i file per ricatenarli, avrei bisogno di almeno 30 GB di spazio di archiviazione per archiviare i file non compressi. Potrei, ovviamente, quindi cattutti i file non compressi xzper ricomprimerli:

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

So come potrei concatenare due file dalla riga di comando senza un intermedio, supponendo che uno fosse non compresso e uno compresso:

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

Ma questo funzionerà solo per un file e uno di essi deve essere già non compresso.

Non sono sicuro se posso solo insieme cati vari file .xz - supponiamo che possano essere stati compressi con parametri diversi.

A un livello superiore, la domanda stessa potrebbe essere posta: puoi prendere l'output di più (più di due) comandi, concatenare tali output e reindirizzarli in un altro processo senza file intermedi? (Scenario ipotetico: immagina che sto facendo una sorta di elaborazione su tutti e quattro i file molto grandi usando uno script che genera output su stdout e che voglio mettere l'output in un altro file compresso.)

È possibile farlo usando solo i comandi di shell?

Risposte:


4

La xzdocumentazione dice

È possibile concatenare i .xzfile così come sono. xzdecomprimerà tali file come se fossero un singolo .xzfile.

Dai miei test, questo funziona anche se i diversi file sono compressi con diverse opzioni; così nel tuo caso

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

funzionerà bene.

Per rispondere alla tua domanda più generale, puoi reindirizzare l'output di un comando composto, ad es

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

o qualsiasi subshell. Ciò consentirebbe di eseguire qualsiasi elaborazione desiderata sui file di registro prima di ricomprimerli. Tuttavia, nel caso di base neanche questo è necessario; puoi decomprimere e ricomprimere tutti i tuoi file eseguendo

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

Se aggiungi -fquesto, funziona anche con file non compressi, quindi

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

ti permetterebbe di combinare registri non compressi e compressi.


Eccellente! Grazie. Due persone hanno risposto con la for file insintassi, vorrei poter dare lo stato "corretto" a entrambi! Ma questa risposta è più completa, quindi eccoti.
fdmillion,

1

provare

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

(questo può essere sottolineato ovviamente).

per aggiungere un nuovo file non rappresentato, usare una sotto shell ( ())

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

0

xzcat -fè la risposta alla prima parte della tua domanda. Ma hai ragione: non puoi semplicemente cat *xz | xzcatse alcuni dei tuoi file sono compressi -F lzma.

A un livello superiore, la domanda stessa potrebbe essere posta: puoi prendere l'output di più (più di due) comandi, concatenare tali output e reindirizzarli in un altro processo senza file intermedi?

Il problema qui è: Se non si memorizza l'output intermedio in file dove si fa lo store?

Se lo memorizzi nella RAM, sei limitato dalla quantità di RAM libera. Se vai oltre, la tua macchina sta rapidamente andando verso lo swaphell.

GNU Parallel archivia in file temporanei, ma se li metti in un tmpfsfile system, sono sostanzialmente memorizzati nella RAM:

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

Se, tuttavia, è accettabile mescolare l'output su base riga per riga, è necessario memorizzare una sola riga da ciascuno dei programmi in esecuzione nella RAM.

Questo è ciò che GNU Parallel (> versione 20170822) fa:

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

Una terza soluzione è quella di comprimere i file temporanei utilizzando un compressore veloce (per esempio pzstd, pigz, lz4, lzop):

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

(GNU Parallel rileva automaticamente quale compressore veloce è stato installato).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.