I am working on VM Linux Ubuntu and my goal is to form this input
4,4
3,8
4,2
4,8
6,8
5,1
4,5
6,9
4,2
5,4
5,9
5,9
7,2
4,9
4,4
5,1
to this output
4,4 6,8 4,2 7,2
3,8 5,1 5,4 4,9
4,2 4,5 5,9 4,4
4,8 6,9 5,9 5,1
And copy these values to an Excel file on Windows.
I wrote this command
cat text.txt |cut -f3| awk '1 ; NR%4==0 {printf"n"} '|pr -4 -t|column -t| tr -s '[:blank:]' 't'
which works fine!
I counted the blanked lines to create each column as below :
cat text.txt |cut -f3| awk '1 ; NR%4==0 {printf"n"} '| awk '!NF {sum += 1} END {print sum}'
–> I got 4 blanked lines, so I am adding 4 to this command |pr -4 -t|
My issue was when I had a larger file, let’s say 160 lines (40 blanked lines).
Initially, the modification on this part |pr -40 -t
gave an error of pr: page width too narrow
so I changed to
cat text.txt |cut -f3| awk '1 ; NR%4==0 {printf"n"} '| pr -W200 -40 -t | column -t| tr -s '[:blank:]' 't'
which seems to work; however, the copy and paste merges 4 values in the 26th column, like
4,83,6
5,66,2
6,57,6
8,18,1
instead of
4,8 3,6
5,6 6,2
6,5 7,6
8,1 8,1
Even though I tried different values on the W
option, I assume that -W200 is responsible for this issue.
I have two questions.
- Can a good proportion between the wide and blanked cells be found to fix this merging issue?
- As my goal is to “paste” 4 lines next to each other, could someone help me to paste the values directly instead of counting the number of blanked lines first and then modifying the wide range as I did?
I really appreciate any help you can provide.
6
Answers
Instead of trying to reverse-engineer and understand OP’s current code, and since OP is already using
awk
, I’d like to propose a singleawk
script to replace all of OP’s current code:NOTE: you can remove the
sub(/r$/,"")
if you know for a fact the input file will never contain dos/windows line endings (r
); if the file does not includer
line endings then thesub(/r$/,"")
becomes a no-op that does nothing (other than use up a few cpu cycles)For 4 lines (
n=4
) of output:For 3 lines (
n=3
) of output:For 7 lines (
n=7
) of output:Another simple approach is to buffer the elements in an array using string concatenation in
awk
. No other process is needed, e.g.Essentially you build a 4-element array with each element being one of the final rows you want in your output. You concatenate every 4th value to each array element
1, 2, 3
and4
in order, adding a space before each value after the first in each element.After having read and concatenated all values into your array, you simply loop over the array elements in the
END
rule outputting each.In an easier to read expanded form that would be:
(adjust for whitespace as needed)
Example Use/Output
Using a heredoc to feed your example to
awk
you can do:Using any awk:
Here is a Ruby to do that:
Prints:
If the line count length of your input is potentially not a perfect mutiple of the number of desired columns (ie, if your input is 15 lines or 17 lines rather that 16 lines which is an even multiple of 4) then you can do something like this:
Prints:
That is the same behavior as
pr
.If you have access to GNU datamash, here is yet another solution. I added a few numbers to your example to show what happens with an item total not divisible by 4.
The paste command puts 4 items at a time from your list into a single line with items separated by a single space. GNU datamash then transposes the resulting table and separates the items with a single space.
Please note that this answer gives you a space-separated table. If you want a tab-separated table, the code is simpler:
Also, if you would like to make the length of the columns 7 (for example) instead of 4, you can do
(tab-separated, but not obvious in this Stack Overflow display)
Bash approach for example, read these values as an array:
and process like this:
output:
Hardcoded variant: