Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

On the subject of optimizing tput, this article mentions using hard-coded strings. Another approach (for some tput commands) is to run the command once, save its output in a variable, and re-use it.

For example, a slow version of printing a blank chess board:

   #! /bin/sh
   
   for rowpair in 1 2 3 4
   do
     for colpair in 1 2 3 4
     do
       echo -n " $(tput rev) $(tput sgr0)"
     done
     echo
   
     for colpair in 1 2 3 4
     do
       echo -n "$(tput rev) $(tput sgr0) "
     done
     echo
   done
And a faster version:

   #! /bin/sh
   
   rev=$(tput rev)
   sgr0=$(tput sgr0)
   
   for rowpair in 1 2 3 4
   do
     for colpair in 1 2 3 4
     do
       echo -n " $rev $sgr0"
     done
     echo
   
     for colpair in 1 2 3 4
     do
       echo -n "$rev $sgr0 "
     done
     echo
   done
In many cases, tput is doing doing anything more than looking up a string and printing it. Though in other cases like "tput cols", it is doing more. (And anyway, the number of columns isn't a constant.)


As the headlined page is about portable shell script coding, note that the -n option to the echo utility is not portable. You should be using printf here, to be in the spirit of the headlined page. (And you should also be quoting variable assignments for safety.)

There's a long history to this, which starts with the fact that adding any option support at all to the original echo breaks stuff. The result over the years has been quite a mess. The current Single Unix Specification has an note stating outright that one should simply not use -n or escape sequences at all with echo if one desires portability, and also stating that one should use printf instead.

* https://unix.stackexchange.com/q/65803/5132

* https://pubs.opengroup.org/onlinepubs/9699919799/utilities/e...


Thanks. With "echo", I am probably stuck in the past. I recall encountering systems where "printf" (the command) didn't exist. Maybe this is no longer a concern.

I'm less sure whether the quoting is technically necessary. It's probably better style to quote anyway, so this is mostly academic, but I'll ask anyway.

Does word splitting, etc. occur when assigning a command substitution to a variable? I know there are times when it does occur:

    $ for i in $(echo a b c)
    > do
    >   echo "$i"
    > done
    a
    b
    c
But then, empirically, when assigning to a variable, anything I throw at it seems to come through unscathed even without quotes:

    $ x=$(echo " * " b c"'"; echo d;)
    $ echo "$x"
     *  b c'
    d
    $ 
No wildcards were expanded, spaces and quotes weren't stripped, etc.

I couldn't find in the standards doc (that you linked) anything that addresses this either way.


It's one of those things where the exact rules are complex and easy to misremember. Ironically, your two scripts demonstrate one way in which the problem arises. The rules are different for each script, because the command expansions are in different contexts. And when someone in the future decides to make your code into a shell function with local variables, suddenly the rules change again.

For maintainability, for safety, for the people who come after one, and for one's own sanity, the general advice is to always quote.

* https://mywiki.wooledge.org/Quotes

* https://unix.stackexchange.com/q/97560/5132

* https://unix.stackexchange.com/q/68694/5132

* https://unix.stackexchange.com/q/131766/5132


And you can of course put the whole chessboard in a string ...

   blackwhite=$(tput rev; echo -n " "; tput sgr0; echo -n " ")
   whiteblack=$(tput sgr0; echo -n " "; tput rev; echo -n " ") 
   row_odd=$(for col in {1..4}; do echo -n "$whiteblack"; done; echo)
   row_even=$(for col in {1..4}; do echo -n "$blackwhite"; done; echo)
   chessboard=$(for i in {1..4}; do echo "$row_odd"; echo "$row_even"; done;tput sgr0)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: