<> == How do I print a horizontal line of characters like ----? == There are ''many'' different ways, depending on how fancy you'd like to be. This page is a restoration of content from the now-defunct bash-hackers wiki, with some additional text. === The simplest way: Just print it === {{{ printf '%s\n' -------------------- }}} This does exactly what it looks like, no more, and no less. If you want a variable number of hyphens, continue reading. === Iterative ways === This one simply loops 20 times, always prints a hyphen, and adds a newline at the end. The number of loop iterations may be changed by passing a value in a variable: {{{ for ((i = 0; i < 20; i++)); do printf %s - done echo }}} The `printf` command uses unbuffered I/O, so it ''actually writes'' a hyphen once per loop iteration. This may be unappealing (e.g. too slow) in some applications. If you prefer to print the entire line all at once, you can build it up in a variable first: {{{ line= for ((i=0; i<20; i++)); do line+=- done printf '%s\n' "$line" }}} === Implicit printf looping === This one uses the `printf` command to print an '''empty field''' with a '''minimum field width''' of 20 characters. The text is padded with spaces, but since there is no text, you get 20 spaces. The spaces are then converted to `-` by the `tr` command. {{{ printf '%20s\n' | tr ' ' - }}} Without an external command, using the (non-POSIX) substitution expansion and `-v` option: {{{ printf -v res %20s printf '%s\n' "${res// /-}" }}} === Sizing it to the terminal === This is a variant of the above that uses the `$COLUMNS` variable if it's set, or `tput cols` otherwise, to find the width of the terminal and set that number as the minimum field witdh. {{{ printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - }}} === Fancy printf tricks === This one is a bit tricky. The format for the `printf` command is `%.0s`, which specifies a field with the '''maximum''' length of '''zero'''. After this field, `printf` is told to print a dash. You might remember that it's the nature of `printf` to repeat, if the number of conversion specifications is less than the number of given arguments. With brace expansion `{1..20}`, 20 arguments are given (you could easily write `1 2 3 4 … 20`, of course!). Following happens: The '''zero-length field''' plus the dash is repeated 20 times. A zero length field is, naturally, invisible. What you see is the dash, repeated 20 times. {{{ # Note: you might see that as ''%.s'', which is a (less documented) shorthand for ''%.0s'' printf '%.0s-' {1..20}; echo }}} This variant requires bash 4.2 or newer: {{{ printf '%(-)T' {1..20}; echo }}} It (ab)uses the `%(timefmt)T` feature, passing a time format string with no date or time elements. A major drawback of these examples is that it's ''difficult'' to pass a length parameter to them, because `{1..$n}` [[BashPitfalls#pf33|doesn't work]]. The standard workaround is to use `eval`: {{{ n=20 eval "printf '%(-)T' {1..$n}"; echo }}} This works well, but you '''must ensure''' that the content of `$n` [[BashFAQ/054|is a valid number]]. Likewise, for the `%.0s-` example, and if we want to size it to the terminal: {{{ # Note: COLUMNS should be sanity-checked first. # Note: we call tput *outside* of the eval, but ensuring a safe PATH is still wise. c=${COLUMNS:-$(tput cols)} eval "printf %.0s- {1..$c}"; echo }}} Or restrict the length to 1 and prefix the arguments with the desired character. {{{ # COLUMNS should be sanity-checked first. c=${COLUMNS:-$(tput cols)} eval "printf %.1s -{1..$c}"; echo }}} ==== The Crazy ormaaj Way™ ==== This one completely depends on Bash due to its brace expansion evaluation order and array parameter parsing details. As above, the eval only inserts the COLUMNS expansion into the expression and isn't involved in the rest, other than to put the `_` value into the environment of the `_[0]` expansion. This works well since we're not creating one set of arguments and then editing or deleting them to create another as in the previous examples. {{{ _=- command eval printf %s '"${_[0]"{0..'"${COLUMNS:-$(tput cols)}"'}"}"'; echo }}} '''Note''': This example no longer works in bash 5.0 or higher. === Using parameter expansions === Preparing enough hyphens in advance, we can then use a non-POSIX subscript expansion: {{{ hr=---------------------------------------------------------------\ ---------------------------------------------------------------- printf '%s\n' "${hr:0:${COLUMNS:-$(tput cols)}}" }}} The drawback to this is that the terminal may be wider than our variable. Here's a more flexible approach, and also using modal terminal line-drawing characters instead of hyphens: {{{#!highlight bash # Requires bash (local variables, $'' and (( )) command) hr() { local start=$'\e(0' end=$'\e(B' line='qqqqqqqqqqqqqqqq' local cols=${COLUMNS:-$(tput cols)} while ((${#line} < cols)); do line+="$line"; done printf '%s%s%s\n' "$start" "${line:0:cols}" "$end" } }}} This one builds up the `line` variable until it's ''at least'' large enough for the terminal, then prints a substring that's exactly the width of the terminal. The modal line-drawing characters may not work in all terminals.