Bash then sorting it

Bash then sorting it



Hey guys so i have this sample data from uniq-c:


100 c.m milk
99 c.s milk
45 cat food
30 beef



desired output:


beef,30
c.m milk,100
c.s milk,99
cat food,45



the thing i have tried are using:


awk -F " " 'print $2" " $3 " " $4 " " $5 "," $1' stock.txt |sort>stock2.csv



i got :


beef ,30
cat food
,45
c.m milk
,100
c.s milk
,99



think its because some item doesn't have 2,3,4,5 and i still use " ", and the sort in unix doesn't prioritise dot first unlike sql. however i'm not too sure how to fix it





On which system are you running this? From what I notice, i.e. the single line split into multiple lines, it seems like you have some special form of a carriage return or line feed in there. You see this as after every last word in the original file, a new line-feed appears with exception of the word "beef" as it is the last word in the file. What is the outcome of file stock.txt and could you try first to convert your file stock.txt to a unix file using dos2unix stock.txt.
– kvantour
Aug 21 at 9:20


file stock.txt


stock.txt


dos2unix stock.txt




5 Answers
5



To obtain your desired output you could sort first your current input and then try to swap the columns.


sort



Using awk, please give a try to this:


awk


$ sort -k2 stock.txt | awk 't=$1; sub($1 FS,""); print $0"," t'



It will output:


beef,30
c.m milk,100
c.s milk,99
cat food,45





sub($1 FS,"") will fail when $1 contains regexp metacharacters. Never use input data in a regexp context unless you have a specific purpose in mind that requires that.
– Ed Morton
Aug 21 at 11:41


sub($1 FS,"")


$1



i think you can solve it in bash using some easy commands, if the format of the file is as you posted it:



prova.txt is your file.



then do:


cat prova.txt | cut -d" " -f2,3 > first_col
cat prova.txt | cut -d" " -f1 > second_col
paste -d "," first_col second_col | sort -u > output.csv
rm first_col second_col



in output.txt you have your desired output in CSV format!



EDIT:



after reading and applying PesaThe comment, the code is way easier:


paste -d, <(cut -d' ' -f2- prova.txt) <(cut -d' ' -f1 prova.txt) | sort -u > output.csv





You could use process substitution to avoid using temporary files: paste -d, <(cut -d' ' -f2- data) <(cut -d' ' -f1 data).
– PesaThe
Aug 21 at 8:37



paste -d, <(cut -d' ' -f2- data) <(cut -d' ' -f1 data)





didn't know this: it will make a lot of my code way easier!
– gabrielet
Aug 21 at 8:40



Combining additional information from this thread with awk, the following script is a possible solution:


awk


awk ' printf "%s", $2; if ($3) printf " %s", $3; printf ",%dn", $1; ' stock.txt | LC_ALL=C sort > stock2.csv



It works well in my case. Nevertheless, I would prefer nbari's solution because it is shorter.



You can use sed + sort:


sed + sort


sed -E 's/^([^[:blank:]]+)[[:blank:]]+(.+)/2,1/' file | C_ALL=C sort




beef,30
c.m milk,100
c.s milk,99
cat food,45





I suspect that this is locale-dependent, since I get cat before c.m if I use this.
– Tom Fenech
Aug 21 at 8:37


cat


c.m





Hmm may be LC_ALL=C sed -E 's/^([^[:blank:]]+)[[:blank:]]+(.+)/2,1/' file | sort would be better
– anubhava
Aug 21 at 8:41


LC_ALL=C sed -E 's/^([^[:blank:]]+)[[:blank:]]+(.+)/2,1/' file | sort





@anubhava Shouldn't you pass LC_ALL=C to sort instead of sed?
– PesaThe
Aug 21 at 8:43



LC_ALL=C


sort


sed





Good point @PesaThe, I have edited it now
– anubhava
Aug 21 at 9:02


$ awk '$0=$0","$1; sub(/^[^[:space:]]+[[:space:]]+/,"") 1' file | LC_ALL=C sort
beef,30
c.m milk,100
c.s milk,99
cat food,45






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)