I have a data like this:

cat file

The output I want is:

(45679900 56789800)
(56783300 67343400)

I want to cancel out the decimal and let it become 8 digit and delete the comma sign and let it be spacing between each others.

Using awk command, how to do it? sed is also ok.

  • Did you take into account that some numbers might be of a different length? – Julie Pelletier Sep 16 '16 at 3:10

Using awk:

awk -F'[(),]' '{ printf( "(%d %d)\n", $2 * 10000, $3 * 10000 ); }' file

sed -e 's/,/ /' -e 's/\.\(..\)/\100/g'


TXR awk macro: we can actually do this as typed operations: get the data as floating-point values, floor them down to nearest integer, multiply by a hundred, convert to integer.

However, let us pause for a moment and reflect that this may be a bad idea if the values are so large that they cannot be truncated to the nearest integer; doing this text-wise will be correct for arbitrarily large values.

$ txr -e '(awk (:begin (set ft #/\d+.\d+/))
               ((mf tofloat floor toint (* 100))))'
(4567.99, 123.45, junk 3.1415, 1.0 ...) x
456700 12300 300 100

The ft variable is a new feature; classic Awk has no equivalent. Whereas fs is like FS (field separator), ft means "field tokenize": it specifies a positive regex which recognizes and extracts fields, ignoring non-matching stuff in between.

Ironically ft can directly express the semantics of the default field separator in Awk: trimming leading and trailing newlines and blanks from the record and separating on one or more newlines or blanks. That is precisely equivalent to simply positively recognizing the fields as tokens consisting of non-blanks! If Awk had an FT variable, it wouldn't need the special hack which applies when FS is equal to a single space; the default could be that FS is not set, and FK is set to the regex [ \t\n]+.

We use a simple ft which recognizes digits, a mandatory decimal and mandatory digits. No leading sign, no optional parts.

The mf macro ("map fields") puts each field through a pipeline of operations. Firstly the tofloat function converts the strings to floating-point. Then floor truncates to the nearest integer, toward negative infinity. toint takes us back to inger and (* 100) denotes the partial application of * to 100: a function which takes additional arguments and multiplies 100 by their product. This partial application syntax follows from the fact that mf arguments are implicitly treated as op syntax: the TXR Lisp explicit partial application operator.

Since mf returns a non-nil result, the default action (prn) kicks in to print the updated rec, which is re-constituted by catenating the updated fields with the default ofs consisting of one space character, and outputting an ors which defaults to newline.

Here is a way to do it numerically, yet without relying on floating-point math. Basically we can extract the fields using the same regular expression, but then remove the dot while they are still text. Then go to integer and use truncating integer division and multiplication:

 $ txr -e '(awk (:begin (set ft #/\d+.\d+/))
                ((mf (remq #\.) toint (trunc @1 100) (* 100))))'

Since integers can be arbitrarily large in this language, this solution doesn't suffer from problems due to the numbers being large, yet minimizes the text processing.

awk '{gsub(/\./,"")sub(/,/," "); print $1"00",$2}' file
(45679900 567898)
(56783300 673434)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.