1

I thought of playing around a bit with find -fprintf. In case you don't know what -fprintf does, it is the same as -printf but writing to a file you specify its name.

Now, when I run a command like this:

find -maxdepth 1 -type d  -fprintf output "%p\b\n"

I get the following in output (using vim and pretty much any text editor):

.^H
./directory-1^H
./directory-2^H
./directory-3^H

I understand that ^H is the backspace character. Opening output with less:

./directory-
./directory-
./directory-

So, the question is:

  1. Why do vim and other text editors (tried nano, and emacs) display the backspace without interpreting it by removing the character before it but less does?
  2. Why don't the editors print a character for \n instead of going down for a new line?
  3. What is the difference between printing a backspace and hitting backspace on the keyboard (a character gets actually deleted on hitting backspace on the keyboard)?

I'm running this on my machine (laptop) without sshing anywhere. Using GNU/Linux Ubuntu 16.04 LTS with konsole and tmux.

4
  • 3
    I think it's because less like more are pager and the others are editors. You can get the same display with less with the -U option.
    – ctac_
    Commented Oct 16, 2018 at 20:28
  • Alright. Then why don't the editors print a character for \n instead of going down for a new line? And what is the difference between printing a backspace and hitting backspace on the keyboard (a character gets actually deleted on hitting backspace on the keyboard)?
    – joker
    Commented Oct 17, 2018 at 7:51
  • Since I found this while looking for printf and backspace (\b) without a file,I wanted to say the following about output on a bash terminal. (I didn't want fprintf.) Let's use printing an array within square brackets with delimiter, , - python style. From my bash (on Cygwin, BTW), declare arr=( 1 2 3 4 ). First look without backspace: printf '['; printf '%s, ' "${arr[@]}"; printf ']' => output [1, 2, 3, 4, ]. If we think the comma and space (2 characters) are "extra", use 2 '\b', i.e. printf '['; printf '%s, ' "${arr[@]}"; printf '\b\b]', => output [1, 2, 3, 4]. Commented Oct 6, 2021 at 15:47
  • Note that, if I redirect this to a file using printf '[' >> myfile; printf '%s, ' "${arr[@]}" >> myfile; printf '\b\b]' >> myfile, I get the same behavior you do. I start with cat myfile (oh no! the vicious "cat for display"), and get [1, 2, 3, 4]. Next, less myfile gives me [1, 2, 3, 4] (and I press [q]). Using vim myfile, (unless I change formatting options, e.g. by using .vimrc), I get [1, 2, 3, 4, ^H^H]. Same result with emacs myfile as with vim myfile. If you want cat to output in the format of vim and emacs, cat -ETv myfile gives output [1, 2, 3, 4, ^H^H]. Commented Oct 6, 2021 at 16:24

2 Answers 2

5

Why do vim and other text editors (tried nano, and emacs) display the backspace without interpreting it by removing the character before it but less does?

Why should they? FWIW, neither do browsers :-)

$ printf "<html>foo\bbar</html>" > /tmp/foo.html
$ firefox /tmp/foo.html

Should editors also interpret other kind of markup, like mini-Markdown *foo* or **bar**?

Notice that backspace isn't just "deleting" the previous char in less, but it's used as a crude formatting character. x\bx will print x in bold, and x\b_ will underline it (which on some terminals will cause it to be printed with a different color):

printf "H\b_e\b_r\b_e\b_'s\bs Johnny!" | less

Why don't the editors print a character for \n instead of going down for a new line?

They could do that. For instance, if you use :set list in vi, newlines will be printed as $ and tabs as ^I.

What is the difference between printing a backspace and hitting backspace on the keyboard (a character gets actually deleted on hitting backspace on the keyboard)?

On a hard-type terminal (printing on paper), printing a backspace was causing the carriage to go one position to the left, so a subsequent char would overwrite, not delete what was already on the paper. On glass (CRT) and emulated terminals, moving a position to the left and writing a character creates an 'erase' effect because overwriting a character replaces it completely. But the \b by itself does not remove anything: printf "123\b\n" will print 123 not 12.

The latter is a function of the tty driver, which interprets some input characters as editing/control commands (erase, werase, intr, kill -- look at the stty(1) or termios(3) manpages for the full list).

And the backspace key does not always generate a \b / ^H (BS) character. Most of the time is \x7f / ^? (DEL).

But you can set it to whatever you like:

$ stty erase '#'

Now hitting # will erase the previous char, like in unix v7.

3
  • 1
    For the part regarding printing \n instead of going down for a new line. I understand that vim displays the \n as $ when :set list. The question is: why doesn't it display a\nb on a single terminal line with \n in the middle instead of going one line down? vim interprets \n as we are expecting it to, by moving down one line and not printing a character indicating the new line with the rest of the text around.
    – joker
    Commented Oct 17, 2018 at 10:31
  • 1
    because that's the user's expectation, to have text files displayed 2-dimensionally; but you can force vim to display the whole file on a single line by setting the newline separator to CR as on (older?) Macs with eg. :e ++ff=mac file
    – user313992
    Commented Oct 17, 2018 at 10:42
  • I was wondering why I got the behavior shown in my comment to the OP. That is, why did arr=( 1 2 3 4 ); printf '['; printf '%s, ' "${arr[@]}"; printf '\b\b]' "erase" the ending , , while, as you said, " printf "123\b\n" will print 123 not 12. ". I played around a bit: printf '123\b\n' => 123(\n). printf '123'; printf '\b' => 123. printf '123'; printf '\b\b'; printf '\n' => 123(\n). printf '123'; printf '\b'; printf ']' =>12]. printf '123\b\b]\n' => 1]3(\n). Some clarification, some confusion. This was helpful. Commented Oct 6, 2021 at 16:50
2

File contents are what applications make of them.

One of the features of the design of Unix was that files are undistinguished sequences of bytes, and it is up to applications to place whatever interpretation that they like upon them.  Applications can and do interpret file contents differently, and you are experiencing the consequences of this.

VIM is interpreting the file contents in accordance with the Single Unix Specification's notion of a Text File, which is a file comprising zero or more lines terminated by and containing no characters. It turns unprintable characters into various printable representations, but is always the end of a line because that is part of the concept.

Other utilities interpret file contents differently. One family of them interprets file contents as a stream of Teletype Model 37 (TTY-37) output data. This family comprises several conventional Unix and GNU programs: less, more, most, ul, colcrt, ncal, grotty in non-default mode, and others. In this interpretation, the character moves the (conceptual) print head back one position and overstrikes what was there before. Because these programs are not physical TTY-37s with ink on paper, they implement their own ideas in software of what overstriking means. Overstriking can variously result in attempts to use boldface and underline attributes, in complete replacement of one character by another, in combined characters, or in nothing at all.

Further reading

2
  • 1
    Thanks mate for the clear answer. Needed to read that.
    – joker
    Commented Dec 18, 2018 at 14:56
  • This is excellent. The explanation is very clear, and the sources are useful. Plus 1 for you. Commented Oct 6, 2021 at 17:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .