bash: Hur sorterar jag en del av flera rader i bokstavsordning?

Trädvy Permalänk
Medlem
Plats
Göteborg
Registrerad
Jun 2004

bash: Hur sorterar jag en del av flera rader i bokstavsordning?

Jag har ett litet kosmetiskt problem som jag gärna skulle vilja få löst. Hur sorterar jag en del av flera rader i bokstavsordning?

Allt mellan början av raden tills två ##. Orden separeras här med comma.

exempel2,exempel4,exempel1,exempel3##inget ska sorteras här efter c,b,a##inget ska sorteras här efter

ska bli

exempel1,exempel2,exempel3,exempel4##inget ska sorteras här efter a,b,c##inget ska sorteras här efter

eller från test= till slutet av raden. Orden separeras här med |.

inget ska sorteras innan här innan,test=b|c|a

ska bli

inget ska sorteras innan här innan,test=a|b|c

Gigabyte GA-Z97X-SLI, Intel Core i5 4460 3.2GHz, 128GB Samsung 850 PRO, Corsair 8GB, Gigabyte GeForce GTX 750ti, EVGA Supernova G2 750W
Min GitHub: https://github.com/lassekongo83

Trädvy Permalänk
Medlem
Registrerad
Jul 2008

Jag har aldrig använt bash tidigare och följande har tagits fram med hjälp av googlande, online-variant av bash samt klipp och klistra. Så antagligen finns det mycket bättre sätt att göra det på. Den löser den första varianten, men bör kunna anpassas för att lösa den andra varianten också.

original="c,b,a##inget ska sorteras här efter" sorted=$(echo ${original%##*}|tr , '\n'|sort|tr '\n' ,|sed '$s/,$/##/')${original#*##} echo $sorted

Ta första delen. Ersätt komma med nyradstecken. Sortera raderna. Ersätt nyradstecken med komma. Byt ut sista kommat med ##. Lägg till andra delen.

Trädvy Permalänk
Forumledare
Registrerad
Okt 2002
Skrivet av johho:

Jag har aldrig använt bash tidigare och följande har tagits fram med hjälp av googlande, online-variant av bash samt klipp och klistra. Så antagligen finns det mycket bättre sätt att göra det på. Den löser den första varianten, men bör kunna anpassas för att lösa den andra varianten också.

original="c,b,a##inget ska sorteras här efter" sorted=$(echo ${original%##*}|tr , '\n'|sort|tr '\n' ,|sed '$s/,$/##/')${original#*##} echo $sorted

Ta första delen. Ersätt komma med nyradstecken. Sortera raderna. Ersätt nyradstecken med komma. Byt ut sista kommat med ##. Lägg till andra delen.

Ser bra ut! Det blir vissa problem med randfall, exempelvis ifall

  1. det finns mer än en förekomst av ## i strängen: c,b,a##inget ska sorteras## här efter

  2. strängen innehåller sekvenser av multipla blanksteg: c   c,b  b,a##inget ska sorteras här efter

  3. om det som ska sorteras innehåller ett element som ser ut som en flagga till echo: c,b,a,-e##inget ska sorteras här efter

Ovanstående saker tror jag i tur och ordning kan adresseras genom att

  1. använda %% för att matcha "girigt" från höger

  2. lägga till citationstecken kring argumenten till echo, eller än hellre gå till printf som generellt beter sig bättre

  3. använda printf med en formatsträng

vilket skulle ge:

original="c,b,a##inget ska sorteras här efter" sorted=$(printf '%s' "${original%%##*}" | tr , '\n' | sort | tr '\n' , | sed '$s/,$/##/')${original#*##} printf '%s\n' "$sorted"


Alternativt är AWK ofta trevligt när det ska hanteras strängar på lite mer komplexa sätt, och det finns färre fällor. Vad gäller hastighet så lönar det sig snabbt att minimera antalet processforkar, så ett enda anrop till awk slår sannolikt att skapa alla ovanstående processer rätt ordentligt, särskilt som indata växer.

Ett AWK-baserat skript (kräver rent tekniskt GNU-varianten gawk pga asort-anropet) som bör lösa uppgiften skulle kunna se ut enligt:

#!/bin/sh awk -F, -vdelim='##' ' { i_delim = index($0, delim); split(substr($0, 1, i_delim - 1), fields); len = asort(fields); for (i = 1; i <= len; ++i) { printf "%s%s", (i > 1) ? FS : "", fields[i] }; print substr($0, i_delim); } ' < "${1:-/dev/stdin}"

Det skriptet agerar då på varje rad i indata, där indata antingen kan komma från en fil som ges som enda argument, eller via stdin, och output skrivs till stdout.

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.

Trädvy Permalänk
Medlem
Registrerad
Jul 2008
Skrivet av phz:

... Det blir vissa problem med randfall, ...

Googlingen lärde mig nog mycket för att bli farlig.
Tack för utbildningen.