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
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.
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 filestock.txt
to a unix file usingdos2unix stock.txt
.– kvantour
Aug 21 at 9:20