sort és awk [megoldva]

Sziasztok.

Adott egy söveges fie, melyben a sorokban vessző a mezőelválasztó (,).
Awk megmondja ugyan, hogy a 6. mezőnek milyen szám a tartalma, de kérdésem az,van-e az awk-nak olyan elvetemült kapcsolója, ami a BASH "sort -n" parancsát helyettesíti?

Azt szeretném, hogy a 6. oszlopban szereplő szám szerint csökkenő sorrendben íródjon ki a szöveges file tartalma.
Meg tudom oldani sok sorral a scriptet, de nem bírom elképzelni, hogy az awk ne tudna ilyesmit. A szöveges file közel 900 MB, sokat javítana a helyzeten, ha kisebb lenne a feldolgozó script.

Kösz minden tanácsot

Hozzászólások

Nekem nem rémlik, hogy a Awk tudna ilyet (fix me). De:


sort -t, -nk6 fityfene.fie

Én is azt mondanám a default awk nem tudja, de lehet ha van fent gawk vagy társai akkor azokban van valami sort funkció man alapján. (asort vagy mi man alapján)

Itt van egy hasonló téma:

https://www.linuxquestions.org/questions/linux-general-1/how-to-use-awk…

A rendezéshez alapból benn kell tartani memóriában a rendezendő adatokat (vannak persze trükkös algoritmusok, amikhez nem kell az összeset benn tartani, de azok pláne nem elérhetőek awk-ban). Az awk meg ponthogy úgy működik, hogy olvassa a sorokat és egyből írja is a kimenetet. Tehát nem tartja benn a sorokat a memóriában. Az awk tehát alapból nem alkalmas a sorok rendezésére. (Nem vagyok awk guru, szóval akár tévedhetek is, de a linkelt topikban sincs tisztán awk-s megoldás.)

A sort-nak viszont van olyan paraméterezése, amivel tud x-edik oszlop szerint rendezni, és az elválasztót is be lehet állítani.


$ sort --help
...
-k, --key=KEYDEF sort via a key; KEYDEF gives location and type
...
-t, --field-separator=SEP use SEP instead of non-blank to blank transition
...

Arra kell vigyázni, hogy ha van escapelés a sorokban, akkor előfordulhat esetleg, hogy valahogy bonyolultabban kell feldolgozni a sorokat. Például CSV-ből ezerféle "szabvány" van, hogy hogy kell helyesen feldolgozni. De ha nincs szabadszöveges meződ, akkor könnyű dolgod van, és működik simán az elválasztók számlálása.

...sokat javítana a helyzeten, ha kisebb lenne a feldolgozó script.
Ezt hogy érted? ;)
Meg kell írni C-ben! Ahhoz nem kell egy sor script sem.

A bash nem rendelkezik sort paraccsal.

A 900MB nem egy méret manapság, bár ha a rekordszámról tudnák valamit...

A feldolgozó script a rendezésen kívül is csinálna valamit?

Háát, elég szörnyűnek tűnik. ;)

Bár ezért tettem fel a kérdéseket.
Az a nagyszerű a klasszikus unix programokban, hogy nem kell nekik sok memória. Ezért aztán egy
awk | sort | awk
parancs (mivel egy pipeline == egy unix command) összesen 10MB körüli memóriát fogyaszt, miközben a feldolgozható adatmennyiség elméletileg korlátlan. Ráadásul a feldolgozás jobbára állandó sebességű, így a futásidő is kalkulálható.

A memóriába töltéshez viszont gondolkozni kell! Ha a rövid fejlesztési idő, de kicsit (kb. 6x) nagyobb futásidő kompromisszum megfelelő, érdemes használni az alap utility programokat.

Csak pontosításképp írom, hogy a sort pipe-ban elvileg sem működhet 10MB memóriában. (A teljes adatsornak random access elérhetőnek kell lennie, a pipe-ban pedig ez nem teljesül.) Vagy RAM-ban, vagy valami tmp fájlban tárolnia kell a teljes adatsort.

(Lásd pl.: Donald Ervin Knuth: A számítógép-programozás művészete)

Ha az IO lassú, kevés a /tmp/, vagy nem elég a RAM, akkor ezek a dolgok számíthatnak.

Mielőtt egy fórumon elkezdeném osztani az észt, először kipróbálom, esetleg még a man-t is megnézem. Én így csinálom, próbáld meg Te is, hátha bejön! ;)

    PID   %CPU  Size   Res   Res   Res   Res Shared   Faults Command
          Used    KB   Set  Text  Data   Lib    KB  Min  Maj
    1811  77.0  4108   648    56   264     0   560    0    0 od
    1810  42.1  8336   648    48   272     0   532    0    0 dd
    1813  32.8  9412  1792    88  1304     0   620   30    0 sort
    1812  19.6  9084   864   348   288     0   708    0    0 awk

A fenti kimenetet az nmon-16d készítette. A parancs (opciók nélkül)
dd |od | awk |sort >file
Konkrétan 12800000 uint32 véletlen számot rendez.

a sort pipe-ban elvileg sem működhet 10MB memóriában
Szóval úgy véled, hogy a

sort file
sort <file
cat file|sort

parancsok esetén a sort más-más mennyiségű memóriát használ?
Miért is? :)

Ehhez nem kell man, mert elvi probléma. Sort esetén addig nem kezdheted el írni a kimenetet, ameddig legalább egyszer végig nem olvastad az inputot. Bizonyítás: előfordulhat, hogy a bemenet utolsó eleme a legkisebb, amit a kimenetre először kell kiírnod. Na most, ha pipe-ban jön és pipe-ba megy az adat, akkor a kimenet első bájtjának írásakor a bemenetet már végigolvasta a processz, tehát az adatokat valahol tárolni kell, különben örökre elvesztek. A ki és bemenetet nem tudja tárolóként használni, tehát "saját magában" kell tárolnia az adatokat, ami praktikusan vagy memória, vagy tmp fájl.

Ha fájlból jön az input, akkor elvileg megteheti, hogy a bemeneti fájlt többször olvassa, ezért elvileg más feladat fájlban lévő adatokat rendezni, mint pipe-ból jövő adatokat. De a gyakorlatban értelmesen ezt nem lehet kihasználni ( O(n*n)-es algoritmussal lehetne csak kihasználni, az meg csigalassú lenne ), úgyhogy ez a felvetésem tényleg hülyeség.

Szerk.: itt van a doksi a paraméterhez, hogy mennyit tart "fejben" és mennyi után nyit tmp fájlokat, amikben rendez. Arra is utal a doksi, hogy valamiféle merge sortot csinál belül:


$ man sort
...
Other options:

--batch-size=NMERGE
merge at most NMERGE inputs at once; for more use temp files
...

Ez mind szép, jó és igaz. Csak nem értem mit bizonygatsz ennyire bőszen. Csak annyit állítottam, hogy kis memóriafelhasználással lehetséges 2xawk+sort futtatása. Azzal is tisztában vagyok hogyan működik a sort. Sőt, azzal meg végképp, hogy unix alatt a legalapvetőbb process szinkronizálási módszer a pipe. A hozzászólást a topicnyitó problémájára írtam.

Sort esetén addig nem kezdheted el írni a kimenetet, ameddig legalább egyszer végig nem olvastad az inputot.
Ez triviális. De ennek sincs semmi köze a pipe-hoz.
...akkor a kimenet első bájtjának írásakor a bemenetet már végigolvasta a processz, tehát az adatokat valahol tárolni kell, különben örökre elvesztek.
Ez is igaz. Egyetlen problémát látok csak az eeepc esetén, ha az adatok nem férnek el több, mint kétszer. Ezt viszont több módon meg lehet kerülni, még pipe esetén is. (Ki mondta, hogy a pipe egyetlen egyenes csőszakasz? ;))

Az a MERGE, mint írja, az egyszerre feldolgozott tmp állományok darabszáma. Bár felfogható merge sort-ként is.

Azért egészítettem ki először, mert félrevezetőnek találtam az "összesen 10MB körüli memóriát fogyaszt" kitételt. Kicsit úgy hangzott, mintha azt mondanám, hogy az elektromos autó ingyen megy, mert nem fogyaszt benzint. Valóban nem fogyaszt, de fogyaszt áramot. Ez meg nem fogyaszt RAM-ot, de fogyaszt diszkterületet.

Annyiban igazad van, hogy a sort írja olvassa a teljes rekordot, amire nincs is szükség, hiszen a 6. numerikus mezőre kell rendezni.
Tételezzük fel, hogy
- ezek a sorok ügyfelek adatai és legalább 100 karakter hosszúak. Ekkor van 9M rekordunk.
- a rekord offset és a szám képezi az indexet, és egy index elem elfér 64 bitben.
- nem ragaszkodunk a script-hez.

Ekkor mmap-pel megnyitva az adatokat, be lehet gyűjteni a 72MB indexet. Ezt a memóriában rendezni, majd a kívánt sorrendben kiírni a sorokat pipe-ba további feldolgozásra. Ez minimum 5x gyorsabb a sort-nál, csak C-ben kell programozni. Viszont 0 diszk írás.

Minden bizonnyal a feldolgozáshoz szükséges többi program elfér 28MB-ban. Így a 900MB adat pont elfér a cache-ben, tehát az adatokat pontosan 1x kell beolvasni. No, meg 1x kiírni.
Ez már jobb?

Köszönöm a gyors válaszokat, megindító volt.
A sort megoldotta a dolgot, az awk tényleg máshogy működik.
A fentieket a későbbiekben még nézegetem, a gawk még hátravan az életemből.

A probléma további része itt folytatódik, érdekességbe átcsapva:
https://hup.hu/node/156139