27

I need a command that will draw a horizontal "line" in the terminal. The line must be exactly the width of the terminal long (regardless of a current terminal width) and consist of a dash character (although a unicode symbol for a horizontal line can be also used).

It is better if it can be colored.

I need to use it like this:

echo some text
drawline
echo more text

And the output would look something like this:

echo some text
---------------------------------------------------------------------------------
echo more text
exebook
  • 32,014
  • 33
  • 141
  • 226
  • 2
    http://wiki.bash-hackers.org/snipplets/print_horizontal_line#a_line_across_the_entire_width_of_the_terminal – Inian Mar 13 '17 at 11:41
  • for zsh: https://superuser.com/questions/845744/how-to-draw-a-line-between-commands-in-zsh-shell – Rufus Jun 29 '18 at 01:20

6 Answers6

34

Try with:

echo some text
printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' -
echo some text
Zumo de Vidrio
  • 2,021
  • 2
  • 15
  • 33
  • 29
    No [attribution](http://wiki.bash-hackers.org/snipplets/print_horizontal_line#a_line_across_the_entire_width_of_the_terminal)? – Benjamin W. Mar 13 '17 at 13:37
  • 3
    Could someone please explain how this works? I'd like to be able to make it shorter by n characters. – Warpling Dec 25 '19 at 04:22
21

In bash and zsh there is the $COLUMNS variable which you can use.

I use this line for that purpose:

printf %"$COLUMNS"s |tr " " "-"

You can also use seq, but this is not as intuitive as the other solution:

seq -s- $COLUMNS|tr -d '[:digit:]'

Edit:

It seems that $COLUMNS is a local bash variable and you will need to export it. So now there are (at least) 2 options.

  1. Export the variable before you call the script:

    export COLUMNS; ./your_script.sh
    
  2. Use tput as Zumo de Vidrio suggests.

    printf %"$(tput cols)"s |tr " " "-"
    
cb0
  • 8,415
  • 9
  • 52
  • 80
  • The thing is that it works on command line but not in the script. – exebook Mar 13 '17 at 14:08
  • 1
    Ok, it seems that I exported the `COLUMNS`, that's why it works. You can either do the same or use a combination of @Zumo de Vidrio and my solution. I updated my answer. – cb0 Mar 13 '17 at 15:22
13

I'll add some details to the current top answer. You can use the following "hack" (also as suggested here):

printf '%.s─' $(seq 1 $(tput cols))

Notice how this doesn't use the simple dash - but instead the box drawing dash . This way consecutive dashes actually connects which prints a nice continuous line:

This nice line   ────────────────────────────
And not this one ----------------------------

You can for example use this to show a line before (and/or after) every command registering hooks using zsh

# ~/.zshrc
draw_hline=false
preexec() {
  if [[ $1 == ls* ]]; then
    hline
    draw_hline=true
  fi
}

precmd() {
  if [ $draw_hline = true ]; then
    hline
    echo
  fi
  draw_hline=false
}

Registering hooks using bash can probably be done in a very similar way using this.

cglacet
  • 8,873
  • 4
  • 45
  • 60
  • In Bash, brace expansion happens first (before command substitution), so you'd get just a single -. To see why, do ```set -x; echo {1..$(tput cols)}; set +x``` and you'll see the echo command as ```+ echo '{1..80}'``` not the numbers 1 thru 80. You can change the evaluation order by doing ```eval printf '%.s-' \{1..$(tput cols)}``` and you'd have to move the - to after the %.s to avoid printf thinking it is an option leader. But, you could get what you want more simply by doing ```printf '%.s-' $(seq 1 $(tput cols))``` without using brace expansion at all. – Steve Amerige Jun 29 '21 at 19:51
  • Strange both `set -x; echo $(seq 1 $(tput cols)); set +x` and `set -x; echo {1..$(tput cols)}; set +x` produce the exact same output on my machine. Both output `echo 1 2 3 … 120 \n 1 2 3 … 120`. Maybe zsh function a different way, I'll update to have a more stable version across shells. Thanks – cglacet Oct 24 '21 at 09:25
4

A simple Perl one-liner
stty size | perl -ale 'print "-"x$F[1]'


NOTE
you can see the height and width of your terminal with stty size


enter image description here

Shakiba Moshiri
  • 21,040
  • 2
  • 34
  • 44
  • great. to clarify: it prints `-` `$F[1]` amount of times. `$F[1]` being the second value (separated by whitespace) of `stty size` command output, eg. `57 228`. i think `print('string'x$number)` is an awesome [tag:perl] construct. –  Jan 31 '19 at 07:49
  • @w17t thank you for your feedback. I am not sure to understand you well. It might you want to use it this way: `perl -le 'print "-" x qx(stty size | grep -o ...\$)'` without `-a` for separators and `@F` array. – Shakiba Moshiri Jan 31 '19 at 08:18
2

you can use tput to set colors and printf to print line according to number of columns.

export RED=$(tput setaf 1 :-"" 2>/dev/null)
export GREEN=$(tput setaf 2 :-"" 2>/dev/null)
export YELLOW=$(tput setaf 3 :-"" 2>/dev/null)
export BLUE=$(tput setaf 4 :-"" 2>/dev/null)
export RESET=$(tput sgr0 :-"" 2>/dev/null)

echo $GREEN some text $RESET
echo $RED; printf -- "-%.0s" $(seq $(tput cols)); echo $RESET
echo $YELLOW more text $RESET

enter image description here

Deepak Deore
  • 284
  • 3
  • 12
-1

Super simple horizontal ruler:

repeat $(tput cols) echo -ne "-";

Inoperable
  • 1,429
  • 5
  • 17
  • 33