Is there a way that I can determine the length of a prompt? Is there a way that I can look at the PS1
variable and get the length from it and repeat characters for the same length?
I am trying to create a new terminal prompt for the bash command.
If your PS1
is well written then it encloses non-printing fragments in \[ \]
. You need to get rid of these fragments first. Normally I would use sed
but I don't think one can easily do non-greedy matching with sed
, hence perl
:
perl -pe 's|\\\[.*?\\\]||g' <<<"$PS1"
A newline inside \[ \]
would make perl
not remove the fragment. This shouldn't happen with well written PS1
, so it's not a problem.
You need the result in a helper variable:
ps="$(perl -pe 's|\\\[.*?\\\]||g' <<<"$PS1")"
A separate variable is needed because the next step is to ask Bash to evaluate the string as if it was a prompt; this is easy with a variable.
One thing though: here string (<<<
) ads a trailing newline, then command substitution ($( )
) removes all trailing newlines. If originally there are no newlines then both phenomena will cancel each other. If there are trailing newlines then you will lose them all and the final result will be off by an unknown number. In a general case we can deal with this by appending a suffix (here X
):
ps="$(perl -pe 's|\\\[.*?\\\]||g' <<<"${PS1}X")"
This way both mechanisms cancel each other for sure. Then you can evaluate as if it was a prompt, like this:
printf '%s' "${ps@P}"
You need the length anyway, so printf
is not exactly necessary:
wc -m <<<"${ps@P}"
I think wc -m
is better than wc -c
in this context. The result is inflated because of our suffix (of length 1) and yet another additional newline (from <<<
). Therefore you need to subtract 2.
The whole procedure as a function:
plen () {
local ps len
ps="$(perl -pe 's|\\\[.*?\\\]||g' <<<"${PS1}X")"
len="$(wc -m <<<"${ps@P}")"
printf '%s\n' "$((len-2))"
}
You said you want to
repeat chars for the same length
Maybe you don't need length for this.
pblock () {
local ps
ps="$(perl -pe 's|\\\[.*?\\\]||g' <<<"${PS1}X")"
ps="${ps@P}"
printf '%s' "${ps::-1}" | tr -c '\n\r' 'M'
}
This function will replicate the shape of the prompt even if it's multi-line, although characters like tab are troublesome. Depending on your tr
multi-byte characters (e.g. ś
) may also make the function not work as expected.
You may or may not prefer printf '%s\n' …
.
echo $PS1
. Also, what you're trying to do exactly.