Like this picture of apt-get, how can I print something at the end of the line, just like the speed on the screen. Although I can use escape like \e[C
to make it move several columns to the right and print, but the speed varies and the string length varies. Can anyone tell me how to do this? I am currently programming using bash. Thanks.

- 517
- 1
- 6
- 21
-
Does it help to your question? [How to add a progress bar to a shell script?](http://stackoverflow.com/questions/238073/how-to-add-a-progress-bar-to-a-shell-script) – Ivan Jan 28 '16 at 03:56
-
Well, actually I've thought of that, but it is kind of trouble to do it manually. – Chromium Jan 28 '16 at 05:42
2 Answers
Often you will find the width of the console window in the environment variable COLUMNS
, but this is not completely reliable. A more reliable solution is to use the tput
utility (part of ncurses, but can be used standalone) with the argument cols
:
$ echo $COLUMNS
148
$ tput cols
148
A simple way to split text is to use the Posix-standard printf
utility to first print the text to be aligned on the right margin padded to the column width, then output a carriage return (\r
) to return the cursor to the beginning of the line, and then print the text to be aligned on the left margin. Finally a newline will move to the next line. Or, in code:
# Call it like this:
# print_both_sides "This goes on the left" "and this goes on the right."
print_both_sides() {
printf "\r%*s\r%s\n" $(tput cols) "$2" "$1";
}
The printf
format uses the standard feature of *
replacements for field width and precision format modifiers; the *
means that the corresponding number should be taken from an argument. In this case, I use $(tput cols)
-- i.e. the width of the console window -- as the first argument for the format code %*s
, which has the effect of right-padding the next string argument ("$2"
) in a field whose width is precisely the width of the console.
I added an additional carriage return to the beginning of the output in case the cursor is currently not at the left margin.

- 234,347
- 28
- 237
- 341
-
The `*` means that the field width should be read from an argument. Other than that, it's a normal `%s` with a field width. Eg., `%80s` would right-pad the string argument in a field of 80 spaces. In this case, I use `$(tput cols)` as the field width argument, which will be the width of the console window. – rici Jan 28 '16 at 07:11
-
That's good. Is there a way to do it using `echo` instead of `printf`? – Chromium Jan 28 '16 at 07:13
-
@Chromium: why would you care? `printf` is posix standard and a bash built-in. Posix recommends that you use `printf` instead of `echo`. – rici Jan 28 '16 at 07:15
-
Oh, really. BUT I still care about that because almost every `stdout` in my program uses `echo`. – Chromium Jan 28 '16 at 07:59
-
The lead sentence is incorrect: `COLUMNS` *may* contain value, but that is more of an exception than a general rule, and usually regarded as a nuisance. – Thomas Dickey Jan 28 '16 at 09:01
-
@ThomasDickey: It should have the correct value if you're using `bash`, but I agree that it is not reliable which is why I didn't use it in the later examples. I changed the lede to note the unreliability of COLUMNS, although it might not be a strongly-worded as you would have written it. – rici Jan 28 '16 at 17:08
In a terminal, there is more than one way to obtain the actual screen-width:
- if the terminal/connection can successfully negotiate the screen size, that (usually) results in a correct value shown in
stty -a
(thecolumns
value usually on the first line of the report). - the command-line
tput
utility consults this information, overriding any constant value for the number of columns from the terminal database, and can print it, e.g,tput cols
. - the environment variables
LINES
andCOLUMNS
usually override that in full-screen applications (including those using curses: seeuse_env
). - sometimes the information is just wrong (see the xterm FAQ Why is my screensize not set?). For terminals supporting the VT100-style cursor-position report (also in ECMA-48, 8.3.14 CPR - ACTIVE POSITION REPORT), you can use
resize
to update thestty
setting and optionally updateLINES
andCOLUMNS
.
When printing using escape sequences, there are a few different ways to use this information about the screen-width, which are widely supported. The command-line tput
utility also can retrieve these from the terminal description (which may lack specific features):
- absolute cursor positioning, allows you to move the cursor to a specific row and column on the screen:
tput cup $row $column
- horizontal cursor positioning, allows you to move the cursor to a specific column on the current row:
tput hpa $column
- relative cursor positioning, allows you to move the cursor left or right (or up or down), a given number of cells, e.g.,
tput cuf $value
to move forward (to the right) by the given number of cells. Regarding the question, using a parameter like this is usually faster than repeating single movements as done withtput
cuf1
.
The capabilities cup
, hpa
, cuf
correspond generally to names in ECMA-48 and are described in the terminfo(5) manual page.
To print text at the right-side of the screen, you would do this:
- obtain the number of columns in the screen,
- determine the number of columns which your text will use,
- compute the starting column: right-margin minus the number of columns in the text
- move the cursor to the starting column
- print the text, e.g., using
echo
orprintf
. The latter has more flexibility.
If you use the command-line printf
utility, you may keep in mind that handling multibyte characters such as UTF-8 is not well-supported when you want to know the width of a given string, so portability may be a concern.
Further reading:

- 1
- 1

- 51,086
- 7
- 70
- 105