Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can "perl -a" somehow re-join @F using the original whitespace?

My input has a mix of tabs and spaces for readability. I want to modify a field using perl -a, then print out the line in its original form. (The data is from findup, showing me a count of duplicate files and the space they waste.) Input is:

2 * 4096    backup/photos/photo.jpg photos/photo.jpg
2 * 111276032   backup/books/book.pdf book.pdf

The output would convert field 3 to kilobytes, like this:

2 * 4 KB    backup/photos/photo.jpg photos/photo.jpg
2 * 108668 KB   backup/books/book.pdf book.pdf

In my dream world, this would be my code, since I could just will perl to automatically recombine @F and preserve the original whitespace:

perl -lanE '$F[2]=int($F[2]/1024)." KB"; print;'

In real life, joining with a single space seems like my only option:

perl -lanE '$F[2]=int($F[2]/1024)." KB"; print join(" ", @F);'

Is there any automatic variable which remembers the delimiters? If I had a magic array like that, the code would be:

perl -lanE 'BEGIN{use List::Util "reduce";} $F[2]=int($F[2]/1024)." KB"; print reduce { $a . shift(@magic) . $b } @F;'
like image 348
piojo Avatar asked Jul 23 '17 08:07

piojo


1 Answers

No, there is no such magic object. You can do it by hand though

perl -wnE'@p = split /(\s+)/; $p[4] = int($p[4]/1024); print @p' input.txt

The capturing parens in split's pattern mean that it is also returned, so you catch exact spaces. Since spaces are in the array we now need the fifth field.

As it turns out, -F has this same property. Thanks to Сухой27. Then

perl -F'(\s+)' -lanE'$F[4] = int($F[4]/1024); say @F' input.txt

Note: with 5.20.0 "-F now implies -a and -a implies -n". Thanks to ysth.

like image 109
zdim Avatar answered Nov 15 '22 05:11

zdim