How can I properly use two-character-width emoji in my bash prompt? - bash

I want to use an American flag emoji in my bash prompt (i.e. PS1 environment variable). However, the American flag emoji causes the terminal cursor to offset an extra character to the right.
πŸ‡ΊπŸ‡Έ is comprised of two unicode characters, πŸ‡Ί and πŸ‡Έ. I believe terminal is converting this to a mono-spaced emoji character (the flag), yet still allocating space for two characters. How can I achieve my expected cursor position?
I want:
πŸ‡ΊπŸ‡Έ Desktop akirna πŸ—½ ls|
I get:
πŸ‡ΊπŸ‡Έ Desktop akirna πŸ—½ ls | << weird space offset before cursor
My ~/.bash_profile is:
export PS1='πŸ‡ΊπŸ‡Έ \W \u πŸ—½ '

Updated Answer
The way your are setting the prompt is not evaluating the escape characters. Add a $ before the string to make it evaluate the escape codes:
pompt$ export PS1='XY \x08: '
XY \x08: echo "Well that didn't work..."
Should become:
pompt$ export PS1=$'XY \x08: '
XY: echo "Escape code success!"
(See Charles Duffy's comment on this answer for why I removed export.)
The example above sets the prompt to the characters X, Y, [space], [backspace], [colon] resulting in a displayed prompt of just "XY:".
On my system, the flag is rendered as two characters (πŸ‡Ί and πŸ‡Έ), so I cannot verify this, but I think adding a backspace (\x08) should work for you:
PS1=$'πŸ‡ΊπŸ‡Έ \\W \\u πŸ—½\x08'
Notes about edits
My original answer suggested using a sub-shell as follows:
export PS1=$(printf "XY \x08")
Many thanks to Charles Duffy for his input~

I worked around this by converting the character to hex, and then putting zero width markers around the second part of the character
so for πŸ‡ΊπŸ‡Έ we get
PS1='\xf0\x9f\x87\xba\[\xf0\x9f\x87\xb8\] '

Related

Why does backtick placement matter?

I'm trying to better understand how backticks work in PowerShell. This works and executes the ipconfig command:
$a = "ipc"
$b = "onf`ig"
iex $a$b
However, if the backtick is moved one character to the left, before the "f", the command breaks...
$a = "ipc"
$b = "on`fig"
iex $a$b
Another example of this:
who`ami
If the backtick is anywhere else, the whoami command will work just fine. With a backtick in the middle, it breaks.
What's happening here? Why does the placement of the backtick's matter so much?
These are becuase some special characters in powershell.
In powershell there are some special characters which are not in standard character set. They start with back tick to show special meaning. They are:
`0 Null
`a Alert
`b Backspace
`e Escape
`f Form feed
`n New line
`r Carriage return
`t Horizontal tab
`u{x} Unicode escape sequence
`v Vertical tab
Here when you escape "a" with backtick
means alert powershell (whoami) and when you escape "f" with backtick means form feed (ipconfig), so both commands break.
And when you escape the other character, commands don't break becuase then characters not render the special meaning.
Though I don't agree with all the author of this article says. Most of the is valid when it comes to use of the graveyard accents\bact tick.
It does have its use cases, but not for what you are showing.
Bye Bye Backtick: Natural Line Continuations in PowerShell]
See also:
about_Special_Characters - PowerShell | Microsoft Docs
PowerShell - Special Characters And Tokens
Grave_accent
Use in programming Programmers use the grave accent symbol as a
separate character (i.e., not combined with any letter) for a number
of tasks. In this role, it is known as a backquote, or backtick.
Many of the Unix shells and the programming languages Perl, PHP, and
Ruby use pairs of this character to indicate command substitution,
that is, substitution of the standard output from one command into a
line of text defining another command. For example, using $ as the
symbol representing a terminal prompt, the code line...
How-to: Escape characters, Delimiters and Quotes

Trouble understanding a bash command

I'm trying to set up a program and came across this line in a bash script. Could someone tell me what it does? I'm not very experienced with bash.
export PS1='\e[0;33mmyProject \e[0;32m\[\e]0;\u#\h: \w\a\]${debian_chroot:+($debian_chroot)}\u#\h:\w\$\e[0m '
Thank you very much!
This command does two things. It sets the title of the terminal window, and
sets the bash prompt.
export PS1='\e[0;33mmyProject \e[0;32m\[\e]0;\u#\h: \w\a\]${debian_chroot:+($debian_chroot)}\u#\h:\w\$\e[0m '
Piece by piece:
export PS1=
This sets the PS1 variable, which is contains the bash prompt.
\e[0;33m
\e is translated to the ESC character (ascii=0x1B), which is a Control Sequence Introducer, which signifies the beginning of an ANSI Escape Code. The m character at the end of the sequence indicates that the everything between [ and m is to be interpreted as a ;-separated list of SGR (Select Graphic Rendition) parameters (See here for more information). The 0 clears all previous text formatting, and the 33 sets the text color to yellow.
myProject
This just adds the string myProject to the bash prompt.
\e[0;32m
This clears all the previous text formatting (0) and sets the text color to green. (32)
\[ ... \]
\[ begins a sequence of non-printing characters which ends with \]. Everything between those two delimiters will not be visible in the prompt.
\e]0;\u#\h: \w\a
This sets the title of the terminal window to something like
username#hostname: /current/working/directory
The next bit:
${debian_chroot:+($debian_chroot)}
If the variable $debian_chroot has been defined, then this expression will evaluate to the value of $debian_chroot.
$debian_chroot is a variable that is set in /etc/bash.bashrc. This post explains it a lot better than I can.
\u#\h:\w\$\e[0m
\u evaluates to the username of the current user, \h evaluates to the name of the computer, and \w evaluates to the current working directory. \$ is just the character $. It needs to be escaped because in bash script, the character $ signifies that the following characters are the name of a variable. \e[0m reverts the text formatting back to default.
An image of what the prompt might look like in a terminal:
This is quite a complicated command you have here!
Let's break it down section by section.
export
This means that we are setting a variable to be used in other programs.
PS1=
The name of the variable is PS1.
\e
This is an escaped character. In bash (and most programming languages), Everything with a backslash before it is an escaped character. It is used for when you need to include a control character like a space, or the control key itself in a string. When it's escaped, bash treats it like it's part of the string, and not another control character.
[
This is the start of an array. It's very similar to an array in a C program.
;
This is an end character, it can mean several different things. Here, it's being used to define part of the array.
There is some other stuff here, but it's mostly just data in the array.
:
This is a NOT operand. It is used to determine the inverse of something.
${debian_chroot:+($debian_chroot)}
This is a variable. In bash, variables start with a $.
It is using the variable debian_chroot and adding it to itself if it's not null.
This command is just defining a variable, in this case an array containing information probably about a chroot with a debian install in it.

Issue with encoding of a character (not able to sed or .gsub)

I am dealing with some multilingual data(English and Arabic) in a json file with a weird character i am not able to parse. I am not sure what the character is. I tried getting the ASCII value via vim and this is what i got
"38 0x26"
This is the status line in vim i used to get the value (http://vim.wikia.com/wiki/Showing_the_ASCII_value_of_the_current_character).
:set statusline=%<%f%h%m%r%=%b\ 0x%B\ \ %l,%c%V\ %P
This is how the character looks in vim -
I tried 'sed' and '.gsub' to replace this character unsuccessfully.
Is there a way where i can replace this character(preferably with .gsub ruby) with '&' or something else?
Thanks
try with something like
sed 's/[[:alpnum:][:space:]\[\]{}()\.\*\\\/_(AllAsciiVariationYouWant)/&/g;t
s/./?/g' YourFile
where (AllAsciiVariationYouWant) is all character that you want to keep as is (without the surrounding "()" )
JSON is encoded in UTF-8 (Unicode). If you're seeing funky-looking characters in your file, it's probably because your editor is not treating Unicode characters properly. That could be caused by the use of a terminal emulator that doesn't support Unicode; an incorrect $LANG setting; vim not being able to correctly determine the encoding of the file; and likely other reasons.
What terminal program are you using? What's your $LANG environment variable set to (echo $LANG)? If you're certain your terminal supports Unicode, try:
LANG=en_US.utf-8 vim your_file_here.json
(The above example assumes that U.S. English is appropriate for the file, which it may not be.)
As for replacing characters in the file, vim's substitution command can be used:
:%s/old text/new text/g
The above command will run the substitute command on all lines in the file (%), replacing every instance of "old text" with "new text". (The g at the end tells vim to replace every instance on a line, not just the first it finds.)

Bash, Always display colored bar at top of screen

Is there anyway to modify the bash profile scripts to always display a colored bar at top of screen. I have a requirement to show a colored hostname, username, and ipaddress on the screen at all times, but i don't want to overload PS1 as it would make the prompt take up over half of the default console width.
Not perfect, but this shows you how to fix part of your prompt on the first row of the screen:
PS1='\w \[\e[s\e[1;1H\e[42m\]\h \u ipaddress\[\e[0m\e[u\]\$ '
A breakdown:
\e[s - save the current cursor position
\e[1;1H - move the cursor to row 1, column 1 (numbered from the upper left-hand corner
\e[u - restore the cursor to the previously saved position
\e42m - make the background green
\e0m - restore the default foreground/background colors
\[...\] - enclose the various non-printing characters so that bash can correctly compute the length of the prompt.
Wikipedia lists other escape codes. The two things missing from this answer are how to extend the bar all the way across the string and how to set the correct IP address.
Update: I believe this covers the changes that ruckc made:
PS1='\[\e[s\e[1;1H\e[42m\e[K\h \u ipaddress\e[0m\e[u\]\w \$ '
How about add a \n inside your PS1, so that you always use a new line with full width?
if you are looking for something less hacky (but maybe overkill), consider byobu
https://en.wikipedia.org/wiki/Byobu_(software)
Alternatively, if you are using xterms, you could set the xterm title instead:
export PS1="\[\033]0;\u $(host $(hostname))\007\]\u#\h:\w\$ "
This sets your xterm title, and sets your prompt to contain username#host:pwd.
My .bashrc contains something like this so PS1 is set correctly depending on whether we're in an xterm or not:
if [[ -n "$TERM" ]] ; then
if ( echo $TERM | $GREP -q xterm ) ; then
export PS1="\[\033]0;\u#\h:\w\007\]\u#\h:\w\$ "
else
export PS1="\u#\h:\w\$ "
fi
fi

Pasting long lines into Mac OS X Terminal

When I paste a long string (ie, more characters than the width of the terminal window), the terminal doesn't autoscroll and put them in multiple lines.
Instead, it basically wraps onto the same line. In other words, it prints until the end of the current line and then starts printing over the existing characters from the beginning of the same line...
Here's a screenshot. Notice the characters "789abc..." at the beginning of the line.
I'm on 10.8.3 with Terminal 2.3. $TERM is xterm-256color.
A colleague has the exact same machine setup (though different Terminal colors and probably other configs) and he can get it to scroll.
Any ideas?
Thanks!
It sounds like you don't have the nonprinting parts of your PS1 prompt string properly marked. The nonprinting parts (e.g. color change escape sequences) -- and only the nonprinting parts -- need to be marked with \[ ... \] so that the shell can tell they don't take up space on screen (and hence can tell where to wrap). For example, my prompt string is \[\e[0;32m\]\h\[\e[m\]:\W \[\e[0;34m\]\u\[\e[m\]$, which parses out as:
\[\e[0;32m\] - change color to green type (nonprinting, so it's wrapped in \[ ... \])
\h - the hostname (printing)
\[\e[m\] - normal print (no color) (nonprinting, hence wrapped)
:\W - the current directory (and delimiters) (printing)
\[\e[0;34m\] - change to blue type (nonprinting)
\u - the hostname (printing)
\[\e[m\] - normal type (nonprinting)
$ - final delimiter before the actual command

Resources