Sloučení více souborů

Založil jahelka, 02. 04. 2020, 15:00:00

Předchozí téma - Další téma

jahelka

Ahoj,
pokouším se spojit různé soubory s různým kódováním (UTF-7, UTF-8, ANSI apod.) a různou znakovou sadou (vietnamština, čínština, čeština, ruština s azbukou apod.). Pomocí cat příkazu nedochází ke znehodnocení znaků, ale vždy když přechází jeden soubor za druhým, tak poslední řádek spojí s prvním. Můžete mi někdo poradit elegantní příkaz, jak spojit asi 2000 souborů do jednoho, aniž by nedošlo ke znehodnocení znakové sady a ještě tam nevznikali nesmyslné řádky při přechodu na další soubor (například nějakým vložením entru mezi přechody u jednotlivých souborů)? Pokouším se vše dělat přes terminál. Děkuji všem za radu (snad jsem to dal i do správného postu).

Roman Horník

#1
Zvláštní koníček :), zkus něco jako:
for soubor in *.txt; do (cat "${soubor}"; echo) >> výstup.txt; done

Platí pro soubory v aktuální složce a příponou *.txt. Echo přidává novej řádek na konec každýho vstupního souboru. Jestli jsou v tý jediný složce soubory s různou příponou (nebo bez), ALE nic jinýho, místo '*.txt' použij jen '*'.
Debian Sid/Experimental 64bit + Mate Desktop Environment
* CPU: Intel i5 3570
* GPU: NVIDIA GTX650 1GD5
* MB: Lenovo IH61M
* RAM: 16GiB Deutsche Demokratische Republik 3 @ 1600MHz

jahelka

Citace od: Roman Horník kdy 02. 04. 2020, 21:51:53
Zvláštní koníček :), zkus něco jako:
for soubor in *.txt; do (cat "${soubor}"; echo) >> výstup.txt; done

Platí pro soubory v aktuální složce a příponou *.txt. Echo přidává novej řádek na konec každýho vstupního souboru. Jestli jsou v tý jediný složce soubory s různou příponou (nebo bez), ALE nic jinýho, místo '*.txt' použij jen '*'.

Děkuji za radu. Nakonec jsem sestavil téměř totožný příkaz ještě před touto odpovědí (pořád mi to nedalo, ale dělal jsem to asi tři hodiny):
for f in *.txt;  do (cat "${f}"; echo) >> vystup.txt; done

Poté jsem zjistil, že sort i uniq nemají rádi čínskou kaligrafii a zanáší chybu, tak to už jsem taktéž vyřešil přes awk, ale narazil jsem na poslední problém a jestli mohu poprosit ještě jednou o radu. To už je na mě moc.

Výstup je nyní
něco1:něco2
nebo
něco1;něco2

A já bych potřeboval vykopírovat každý řádek bez sloupečku něco1 a bez středníku a dvojtečky. Pochopitelně v řádku pak mohou být i další dvojtečky a středníky (ty už jsou součástí něco2). Navíc aby výstup byl jen takto:
něco2
něco2
něco2

A vzhledem k 60GB souboru se může stát, že tam třeba středník nebo dvojtečka nemusí být vůbec. V tomto případě by se řádek měl považovat rovnou za něco2. A i zde platí zachování kódování i znakových sad. Jak říkám, toto už je na mě příliš podmínek. Děkuji chytrým hlavám!

Roman Horník

#3
To jsou všechny řádky na způsob něco1:něco2, respektive něco1;něco2?
Jestli jo a jestli nejsou v oněch sloupcích další středníky / dvojtečky, pak:

awk -F'[:;]' '{print $2}' < vstup > výstup

AWK použije jako oddělovače ":" a ";" (-F'[:;]') a vypíše 2. sloupec ('{print $2}'). Kdyby ve vstupu náhodou byla chyba v podobě dvou (nebo víc) středníků/dvojteček za sebou, použij místo $1 $NF, jinak bude považovat to mezi dvěma oddělovačema za pole 2, tedy prázdno, a to za 2 oddělovačem už je $3, který se nevypíše.

No a pro případ, že na vstupu na začátku nebo na konci některýho z řádků nebo sloupce (oddělenýho ;/:) budeme mít nějakou tu mezeru, pomůže nám sed:

(awk -F'[:;]' '{print $NF}' | sed 's/^\ *//;s/ *$//') < vstup > výstup

Takže ve výsledku:

Vstup:

sloupec1;sloupec2
sloupec1:"sloupec2"
"sloupec1":sloupec2
sloupec1;;sloupec2
sloupec1; 'sloupec2'
sloupec1  : sloupec2


Výstupy:

Výstup $2:
sloupec2
"sloupec2"
sloupec2

'sloupec2'
sloupec2


Výstup $NF:
sloupec2
"sloupec2"
sloupec2
sloupec2
'sloupec2'
sloupec2


Výstup sed & $2 (bez mezer na začátku/konci):
sloupec2
"sloupec2"
sloupec2

'sloupec2'
sloupec2


Výstup sed & $NF (bez mezer na začátku/konci):
sloupec2
"sloupec2"
sloupec2
sloupec2
'sloupec2'
sloupec2
Debian Sid/Experimental 64bit + Mate Desktop Environment
* CPU: Intel i5 3570
* GPU: NVIDIA GTX650 1GD5
* MB: Lenovo IH61M
* RAM: 16GiB Deutsche Demokratische Republik 3 @ 1600MHz

jahelka

Děkuji,
jen právě druhá a další : nebo ; je v podstatě už správně (součást celku), takže by se naopak neměl odstraňovat a měl by vědět, že je to součástí něco2. Takže bych potřeboval něco takového:
vstup:
něco1:něco2
něco1: něco2
něco1:něco2;něco2
něco1:něco2:něco2
něco1:něco2;něco2;něco2
něco1::něco2
něco1::;něco2
něco1něco2

výstup:
něco2
něco2
něco2;něco2
něco2:něco2
něco2;něco2;něco2
:něco2
:;něco2
něco1něco2

Podmínka na způsob jdi do první dvojtečky nebo středníku a od něj vykopíruj zbývající část textu na řádku (bez toho prvního identifikátoru : nebo ;). Ale nesmí v podmínce chybět, aby hledal vždy jen jednu : nebo jeden ; (takže vždy se odstraní jen jedna : nebo jeden středník a zbytek na řádku už je žádoucí). A stejně tak se může stát, že tam nebude žádná dvojtečka, nebo středník, tak pak to celé považovat za něco2. Mezery jsou v tomto případě taktéž žádoucí, jelikož mohou být součástí řetězce něco2. Ta data jsou tak hloupá, že se to špatně vysvětluje. Kdybych je sem nakopíroval, tak by to bylo strašně matoucí, jelikož jsou to nesmyslné řádky. Proto se to snažím vysvětlit na těch označení něco1 a něco2. Děkuji moc!

Roman Horník

#5
Jestli to chceš tak, jak píšeš (ale o víc sloupcích ses nezmínil), pak použij tenhle příkaz: sed 's/^[^:;]*://' < vstup > výstup
Odstraní všechno na začátku řádku po první oddělovač (:, ;), pokud tam ovšem je, a ten odstraní taky.

Pěkně vedle sebe (+ 3 řádky):
--------------[Vstup]---------------|-------[Výstup]------
něco1:něco2                         |něco2
něco1: něco2                       | něco2
něco1:něco2;něco3                   |něco2;něco3
něco1:něco2:něco3                   |něco2:něco3
něco1:něco2;něco3;něco4             |něco2;něco3;něco4
něco1::něco2                        |:něco2
něco1::;něco2                       |:;něco2
něco1něco2                          |něco1něco2
něco1 ;něco2                        |něco2
ně   co1 : něco2                   | něco2
    něco1 :něco2   ;ně co3:něco4    |něco2   ;ně co3:něco4
Debian Sid/Experimental 64bit + Mate Desktop Environment
* CPU: Intel i5 3570
* GPU: NVIDIA GTX650 1GD5
* MB: Lenovo IH61M
* RAM: 16GiB Deutsche Demokratische Republik 3 @ 1600MHz

jahelka

#6
Tak ten poslední se již chová dobře, jen fungoval jen pro dvojtečku. V případě, že tam je středník, tak jej úplně ignoroval.
Opravil jsem ho následovně:

sed 's/^[^:]*://;s/^[^;]*;//' <vstup> výstup

Doufám, že to tak může být? Nemám s ním žádné zkušenosti. Jinak ještě jednou moc děkuji!

Edit: Tak po testování mi to ještě nefunguje pro variantu
--------------[Vstup]---------------|-------[Výstup]------
něco1:něco2;něco3                   |něco3


Roman Horník

#7
Jo aha, nevšiml jsem si, že to nebere středníky, ale budiž: sed 's/^[^;:]*[;:]//' < vstup > výstup

Furt se nemůžu zbavit pocitu, že tam vidím římskej rypák: ^[^ ;D
Debian Sid/Experimental 64bit + Mate Desktop Environment
* CPU: Intel i5 3570
* GPU: NVIDIA GTX650 1GD5
* MB: Lenovo IH61M
* RAM: 16GiB Deutsche Demokratische Republik 3 @ 1600MHz