1

With a given array of underscore separated coordinates (like so: 5_2 4_5 1_3), I need a fast bash function to draw a block character at those locations on the terminal screen. Right now I have this:

function draw() {
    clear
    for i in $(echo $@); do
        y=$(echo $i | cut -d '_' -f1)
        x=$(echo $i | cut -d '_' -f2)
        tput cup $x $y && printf "█"
    done
}

This functions porperly, however it is rather slow - it takes 0.158s to execute it with 8 coordinates. Is there a better and faster way to do this?

k-a-v
  • 326
  • 5
  • 22

2 Answers2

3

I don't know that this is really a great idea, but this refactor runs about twice as fast on my box:

draw() {
    clear
    for i; do
        y=${i%_*}
        x=${i#*_}
        tput cup $x $y && printf "█"
    done
}
William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • This is great optimization! I was also wondering about speeding up the tput line, but if nothing about that is able to be faster I'll mark this as the answer – k-a-v Aug 06 '19 at 00:44
  • 2
    You can use `printf '\e[%d;%dH█' "$y" "$x"` instead of `tput` and `printf '\e[2J'` instead of `clear`. The code will then be entirely fork free – that other guy Aug 06 '19 at 01:04
  • @thatotherguy - These printf commands were exactly what I was looking for, this is lightning fast! – k-a-v Aug 06 '19 at 01:21
  • Printf is definitely faster, but less reliable. For instance, `tput cup 5 8` on my macos is equivalent to `printf '\e[%d;%dH' 6 9`. – William Pursell Aug 06 '19 at 17:50
1

Can you beat this one with awk?:

#!/usr/bin/env bash

coords=( 5_2 4_5 1_3 )

awk 'BEGIN{RS=" ";FS="_"}{printf("\x1B[%d;%dH█",$1+1,$2+1)}' <<<"${coords[@]}"

Or with a POSIX shell:

#!/usr/bin/env sh

coords="5_2 4_5 1_3"

printf '%s\n' $coords | awk -F_ '{printf("\x1B[%d;%dH█",$1+1,$2+1)}'

If you have coordinates into the coords.txt file:

5_2
4_5
1_3

A one line will draw your blocks at coordinates

awk -F_ '{printf("\x1B[%d;%dH█",$1+1,$2+1)}' <coords.txt
Léa Gris
  • 17,497
  • 4
  • 32
  • 41