Why does vi show the ends of lines as $? - ascii

I am using vi on Mac, and when I've run :set list, a $ (dollar sign) character is displayed at the end of each line. My confusion is that $ is not the ASCII value for a newline. Why does $ represent the end of the line?

$ was chosen as the default value to display to represent the line, probably because $ is the command to move the cursor to the end of the line, which was probably chosen because $ represents an end of line anchor in a regular expression. There's nothing magical about it, and you can use any character you want by setting listchars. :help listchars for details.

Related

Why this two-line bash prompt is messing up the command history

I have my bash prompt as:
\u#\H: \w$(__git_ps1 "[\[\e[0;32m\]%s\[\e[0m\]\[\e[0;33m\]$(parse_git_dirty)\[\e[0m\]]")\n\e[1m\t\e[0m $
so the second line is to display current time.
However, I have found it is messing up the history - when use arrow key to move up, a port of command seems get "stuck" and won't change it anymore. The only way I get back is to press Enter again. How to fix it?
\u#\H: \w$(__git_ps1 "[\[\e[0;32m\]%s\[\e[0m\]\[\e[0;33m\]$(parse_git_dirty)\[\e[0m\]]")\n\e[1m\t\e[0m $
# ^^^^^ ^^^^^
All of the ANSI escape sequences on the first line are correctly surrounded by \[ and \], which tell Bash to not to count those characters when figuring out the visual length of the prompt. The ones on the second line are missing these delimiters.
PS1='\u#\H: \w$(__git_ps1 "[\[\e[0;32m\]%s\[\e[0m\]\[\e[0;33m\]$(parse_git_dirty)\[\e[0m\]]")\n\[\e[1m\]\t\[\e[0m\] $'
# ^^ ^^ ^^ ^^

Backspace deletes prompt in terminal

In the following scenario, my bash prompt looks like this:
Username#Hostname ~ $
If I type any number of characters, and then press the delete button one-too-many times, it will clear the entire line. For example:
Username#Hostname ~ $ ls
then I delete s
Username#Hostname ~ $ l
then I delete l
|
I'm then left with my cursor without any sort of prompt. I can type up commands normally and everything seems to function fine--but why does the prompt disappear? Is there a way to stop this behavior?
If you are using escape sequences to color (or otherwise add content) to your prompt without marking the escapes as "non-printing", bash will lose track of the column, and result in behavior like this.
bash's manual suggests that you put nonprinting characters in your prompt within \[ and \] markers.
For the given example
PS1='\[\033[1;32m\u#\h\[\033[00m \[\033[1;34m\w $\[\033[00m '
a possible improved version would be
PS1='\[\033[1;32m\]\u#\h\[\033[00m\] \[\033[1;34m\]\w $\[\033[00m\] '

How to get second-to-last argument from previous bash command? (in an interactive bash shell)

How can I easily get the second-to-last (penultimate) word/argument from the previous command in a bash interactive shell? I often run commands in the background, and I would like to get the file that was specified before the &, e.g.,
% echo foo > /tmp/foo &
% cat !$
% &
In the example above, !$ gives the last word, &. But I want the second-to-the-last argument, /tmp/foo
Note that it is possible to use word designators with a range like !-1:3, but this is impractical for a command with a large number of words where it's not quickly obvious how many words there are, e.g.,
% (set -x; date; pwd; git status; git diff; git log | tail -30; date; args=--verbose time make test; date) >& /tmp/log/make.test.20150122-Thu-0834 &
% echo !-1:30
/tmp/log/make.test.20150122-Thu-0834
The example above works, but you have to count and know that the word you want is the 30th word, which is time-consuming and error-prone.
Is there an easy way to get the second-to-last (penultimate) word?
UPDATE:
Note that I'm looking for something to type on the command line (e.g., a history expansion, like the !! event designator, or the $ word designator), as opposed to using readline key bindings (e.g., the esc key).
(Note that this question refers to the arguments of a previous command in an interactive shell, and not to arguments passed to a shell script from the command-line, as some answers and comments here are referring to.)
Interactively, you can get the second to last argument of the previous command line with esc - 1 esc . with the default bindings.
More generally, the sequence esc . gets the final token from the previous command line, and you can pass it a numeric argument to specify a different one (for example, esc 1 esc . gets the first argument, and esc 0 esc . gets the command itself).
esc is one of the keybindings for Meta; on many modern keyboards, you can use Alt as Meta as well (you press it at the same time, not as a prefix modifier). I prefer esc as meta because when my muscle memory learned these things, we didn't have no (reliable, consistent) Alt key, and it's still portable all the way to VT100 and Sun keyboards; and at least on my current keyboard (Mac OSX Yosemite) e.g. alt-- does something else than specify a negative numeric argument.
From a previous compound command like this
echo moo; echo bar
the sequence esc 2 esc . gets the semicolon, because that's the second token.
I'm sure there is a way with ! history expansion as well, but I vastly prefer to see what I'm doing. This mechanism brings you the text you want to refer to into your current command line, so you can edit it if you like as well.
Use this to run a command using the 3rd argument of the last command in history:
echo foo > /tmp/foo &
cat !-1:3

Removing trailing new line after printing on Mac OS X zsh

i'm trying to print stdin without the trailing new line that appears after using cat, grep, awk etc. (Mac OS X zsh)
Unfortunately, echo -n doesn't work, it prints some weird character.
Do you have any idea on the matter ?
Thanks.
From man zshoptions:
PROMPT_SP <D>
Attempt to preserve a partial line (i.e. a line that did not end
with a newline) that would otherwise be covered up by the command prompt
due to the PROMPT_CR option. This works by outputting some
cursor-control characters,
including a series of spaces, that should make the terminal wrap to the
next line when a partial line is present (note that this is only
successful if your terminal has automatic margins, which is typical).
When a partial line is preserved, by default you will see an inverse+bold
character at the end of the partial line: a "%" for a normal user or a
"#" for root. If set, the shell parameter PROMPT_EOL_MARK can be used
to customize how the end of partial lines are shown.
NOTE: if the PROMPT_CR option is not set, enabling this option will have
no effect. This option is on by default.
Add this to your .zshrc to change the behavior. And note that this is a feature by design, not a bug.
export PROMPT_EOL_MARK=''

Adding ANSI color escape sequences to a bash prompt results in bad cursor position when recalling/editing commands

If I set my command prompt like:
export PS1='\033[0;33m[\u#\h \w]\$ \033[00m'
The color of the prompt will be yellow and everything after the '$' character will
be the default terminal color. This is what I expect. However, If I recall a command line and attempt to edit it, moving the cursor -- either UpArrow/Ctrl-A (set -o emacs) or ESC K (set -o vi)
if the command line I'm trying to edit is long enough, the cursor is not positioned at the beginning of the command. Typing either Ctrl-A (set -o emacs) or ^ (set -o vi) will not move the cursor to what I'm seeing as the beginning of the recalled line on the screen. Similarly, attempting to position the cursor to the end of the line (Ctrl-E or $, depending) results in it being placed several characters past what appears to be the end of the line.
It looks like bash is getting confused by the escape characters I've added to the prompt.
Is this just something I'll have to deal with, changing my prompt to a monochromatic one when I wish to edit recalled lines, or is there a way to get bash to correctly allow the editing of recalled commands with a colorful prompt?
You need to enclose the non-printing characters in \[ ... \] so that bash knows to ignore them when computing the length of the prompt:
export PS1='\[\033[0;33m\][\u#\h \w]\$ \[\033[00m\]'

Resources