2

How to deal with NBSP in a terminal?

The following are the behaviors of me pasting the exact same string (which consists of a leading NBSP) to terminals:

$  echo abc
bash:  echo: command not found

$ echo abc
abc

$  echo abc
-bash: $'\240echo': command not found

$ ls ~/.inputrc
ls: cannot access '/root/.inputrc': No such file or directory

$ ls ~/.bash*
/root/.bash_history  /root/.bashrc

$ cat ~/.bashrc
. . . basically nothing there . . .

$ bind -v | grep bracketed
set enable-bracketed-paste on

$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux bullseye/sid
Release:        testing
Codename:       bullseye

$ uname -rm
5.10.0-6-amd64 x86_64

The NBSP comes from the document that I'm using, be it LibreOffice Writer or google doc etc. So I badly need to get this pasting NBSP working (as my 2nd case), because that's where I document my commands, i.e., I cannot change their behavior.

So,

  • For all three cases, I didn't touch any system default settings or mine
  • In my 2nd case, the working one, I have LANG=C. Both others have utf8 based LANG
  • However, even if I change to LANG=C in the other two, I'm still getting the same error

The "method 1" from this answer does not work for me:

enter image description here

and the bind '"\302\240":" "' approach is not working for me either (this is a new machine with only root user at the moment, so the prompt may look odd):

enter image description here enter image description here

I'm guessing bind '"\302\240" is associating with pressing that key in the terminal, whereas I'm just pasting in. Just guessing.

$ echo $'\240echo abc' | grep -a $'\240'`
 echo abc

nbsp=`echo $'\240'`

$ echo "${nbsp}echo abc${nbsp}${nbsp}${nbsp}def" | grep -a $'\240' 
 echo abc   def

bind "${nbsp}":" "

# then paste in the above echo output, 

$ od -c -
 echo abc   def
0000000 240   e   c   h   o       a   b   c 240 240 240   d   e   f  \n

# paste again to bash, which will become:

$ echo abcdef
abcdef

# i.e., all the spaces have been eaten, instead of mapped as " "

$ tail -5 /etc/inputrc
# map NBSP to regular space (left part has NBSP in quotes, right part has space)
"\240":" "
"\302\240":" "
" ":" "

$ tail -4 /etc/inputrc | od -c -h 
0000000   "   \   2   4   0   "   :   "       "  \n   "   \   3   0   2
0000020   \   2   4   0   "   :   "       "  \n   " 302 240   "   :   "
0000040       "  \n   " 342 220 243   "   :   "       "  \n

All above commands are done in xterm, except the black-screen one, which is from urxvt (which gives 302 240 od -c - output).

Conclusion:

Thanks a lot Kamil, for his persistent help. "It's midnight where I live", he said, but continued "I will check the question in several hours". It's the exact bind commands, and the bind 'set enable-bracketed-paste off' that is the last mile that I need.

bind -r '\240'

bind '"\240":" "'

bind 'set enable-bracketed-paste on'

$  echo abc   def
-bash: $'\240echo': command not found

bind 'set enable-bracketed-paste off'

$  echo abc   def
abc def

Sorry Kamil, I should be more careful following what you suggested.

12
  • Thanks. So the nbsp is Ctrl+Shift+Space in LibreOffice and I'm starting from the right place – roaima May 9 at 16:54
  • OK, my apologies. "I cannot change their behavior" is not equivalent to "I cannot choose tools more suitable for storing code as-is". This misled me. – Kamil Maciorowski May 9 at 17:08
  • That's OK. Thanks for helping. Indeed, I cannot choose tools more suitable for storing code as-is, alongside of my doc/comments/etc, google doc being the main culprit. – xpt May 9 at 17:11
  • @DrMoishePippik, there are actually better options than going through text editors each time, for e.g., here, however, I was not able to make it working on my end. Hence, asking here. – xpt May 9 at 19:27
  • The "method 1" from this answer to the question you linked to actually works and it's way more elegant than my approach (below). IMO you should have admitted in the question body you had found a solution but it doesn't work for you. I'm not removing my answer because it allows to keep NBSPs on-demand. – Kamil Maciorowski May 9 at 19:57
3

Preliminary notes

  • This answer is for NBSPs encoded as \302\240 (in octal representation). \302\240 is for Unicode. In iso8859-1 it's sole \240 (\xa0, see this answer). Adjust solutions if needed.
  • My solutions affect interactive usage that involves Readline. They don't fix unwanted NBSPs in scripts. If you need to fix a script, use sed or whatever to actually fix the code in the script.
  • The solutions should work for typed commands. For pasted commands they will work if enable-bracketed-paste is off (check bind -v | grep bracketed). The solution that overrides Enter will work when Enter is typed, even if enable-bracketed-paste is on and the command was pasted.

Global solution

From this answer on Ask Ubuntu:

Put following in .inputrc […]:

[…]

# map NBSP to regular space (left part has NBSP in quotes, right part has space)
" ":" "

If markdown messes up the above

And it does!

If markdown messes up the above, you have to put NBSP in quotes on the left side of colon as explained in the comment. This will map any occurrence of NBSP on input stream with a regular space.

Readline should understand \302\240. The following version won't be broken by markdown, you can copy it directly:

"\302\240":" "

Note this solution can affect any program that uses Readline and there may be no easy way to disable the solution on demand for a program. In Bash you can disable it by running:

bind -r '\302\240'

And re-enable by:

bind '"\302\240":" "'

Separate instances of Bash can disable the binding independently.


For Bash only

If you want to affect Bash but not other programs that use Readline then put this in your ~/.bashrc:

bind '"\302\240":" "'

Commands to disable and re-enable are exactly like in the previous solution.


Dynamically

This function will turn all NBSPs in the command line into regular spaces:

_fix_nbsp () { READLINE_LINE="${READLINE_LINE//$'\302\240'/ }"; }

Bind it to some unused combination, e.g. to Ctrl+x,j:

bind -x '"\C-xj": _fix_nbsp'

Now you can sanitize the command line by typing Ctrl+x,j.

It may be useful to make Bash do this automatically upon Enter. Normally Enter sends Ctrl+m (verify by Ctrl+v,Enter, you should see ^M), but Ctrl+j should work as well. So let's make Enter send Ctrl+x,j to trigger our function and then Ctrl+j to execute the result:

bind '"\C-m": "\C-xj\C-j"'

Ctrl+j typed manually will still allow you to execute the command line without calling the function. Remember the function turns all NBSPs into regular spaces. If your code contains NBSPs that should survive then you need to fix other (i.e. unwanted) NBSPs manually and execute with Ctrl+j.

Notes:

  • To make the solution permanent, add the function and the bind … command(s) to your ~/.bashrc.

  • If you choose to override Enter then the function will be run even if Enter is going to insert a newline after \ or inside a quoted string (so without execution yet). This shouldn't break things as long as you want NBSPs to be converted. Still running the function multiple times when the final run alone would do the whole job is inelegant. On the other hand the function does not call external utilities like sed, it does its job totally inside Bash, so even calling it multiple times in vain from time to time is not that bad.

    But if you paste a multi-line command where NBSPs should survive (so you're going to use Ctrl+j as advised above) then newline characters being pasted will trigger the function for fragments already pasted. To fix this, investigate bracketed paste.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.