Min GitHub: https://github.com/lassekongo83
bash: Hur sorterar jag en del av flera rader i bokstavsordning?
Visa signatur
Visa signatur
Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.
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
Min GitHub: https://github.com/lassekongo83
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.
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
det finns mer än en förekomst av ##
i strängen: c,b,a##inget ska sorteras## här efter
strängen innehåller sekvenser av multipla blanksteg: c c,b b,a##inget ska sorteras här efter
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
använda %%
för att matcha "girigt" från höger
lägga till citationstecken kring argumenten till echo
, eller än hellre gå till printf
som generellt beter sig bättre
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.
... Det blir vissa problem med randfall, ...
Googlingen lärde mig nog mycket för att bli farlig.
Tack för utbildningen.
Copyright © 1999–2024 Geeks AB. Allt innehåll tillhör Geeks AB.
Citering är tillåten om källan anges.