Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux Bash PS1:外部命令中非打印字符的换行问题_Linux_Bash_Escaping_Command Prompt_Prompt - Fatal编程技术网

Linux Bash PS1:外部命令中非打印字符的换行问题

Linux Bash PS1:外部命令中非打印字符的换行问题,linux,bash,escaping,command-prompt,prompt,Linux,Bash,Escaping,Command Prompt,Prompt,我使用一个外部命令来填充bash提示符,每次计算PS1时都会运行该提示符。但是,当这个命令输出不可打印的字符(如颜色转义码)时,我遇到了一个问题。 以下是一个例子: $ cat green_cheese.sh #!/bin/bash echo -e "\033[32mcheese\033[0m" $ export PS1="\$(./green_cheese.sh) \$" cheese $ # <- cheese is green! cheese $ <now type rea

我使用一个外部命令来填充bash提示符,每次计算PS1时都会运行该提示符。但是,当这个命令输出不可打印的字符(如颜色转义码)时,我遇到了一个问题。 以下是一个例子:

$ cat green_cheese.sh 
#!/bin/bash
echo -e "\033[32mcheese\033[0m"

$ export PS1="\$(./green_cheese.sh) \$"
cheese $ # <- cheese is green!
cheese $ <now type really long command>
是否有一个特定的转义序列可以从外部命令使用,以达到预期的结果?或者,是否有一种方法可以手动告诉提示设置提示宽度的字符数

假设我可以从外部命令打印我喜欢的任何内容,并且该命令可以非常智能(例如,计算输出中的字符)。我还可以根据需要使
export PS1=…
命令变得复杂但是,颜色的转义码必须来自外部命令。


提前谢谢

我无法确切地告诉您为什么这样做,但请在提示符中将
\[
\]
替换为
bash
从它们生成的实际字符:

echo -e "\001\033[32m\002cheese\001\033[0m\002"
[我从一些我现在找不到的堆栈溢出帖子中学到了这一点。]

如果我不得不猜测的话,那就是
bash
在执行嵌入提示符中的命令之前用两个ASCII字符替换
\[
\]
,因此当
green\u cheese.sh
完成时,
bash
要正确处理包装器已经太晚了,所以他们被逐字逐句地对待。避免这种情况的一种方法是使用
PROMPT\u命令
动态生成提示,而不是在
PS1
的值中嵌入可执行代码

prompt_cmd () {
    PS1="$(green_cheese.sh)"
    PS1+=' \$ '
}

PROMPT_COMMAND=prompt_cmd

通过这种方式,
\[
\]
在定义时被添加到
PS1
,而不是在计算时,因此您不需要直接使用
\001
\002

我怀疑,如果您在第一个示例之后重复
$PS1
的值,您会发现它的值是“奶酪”一词绿色的。(至少,这是我运行您的示例时看到的。)乍一看,这就是您想要的-绿色的“奶酪”一词!除了你真正想要的是“奶酪”这个词,它的前面是产生绿色的转义码。您使用echo的
-e
标志所做的是使用已计算的转义码生成一个值

这恰好适用于颜色规范,但正如您所发现的,它将“非打印序列”标记损坏为
$PS1
解释器无法正确理解的内容


幸运的是,解决方案很简单:去掉
-e
标志
echo
将保持转义序列不变,并且
$PS1
解释器将做正确的事情™.

如果无法编辑生成包含ANSI颜色/控制代码的字符串的代码,可以在事实发生后将其包装

以下内容将ANSI控制序列括在ASCII
SOH
^A
)和
STX
^B
)中:

或:


另外,多次运行该功能不会重新转义已转义的控制代码。

谢谢。这很好用!事实上,现在我知道了要使用的转义码,我找到了你提到的其他帖子:你完全正确<代码>\001和
\002
,也称为RL\u提示符\u开始\u忽略和RL\u提示符\u结束\u忽略,是一个缺乏文档记录的错误。Bash将Readline的
\[..\]
转换为
\001..\002
,但忽略了转义现有的代码,因此该实现细节会泄漏(而且非常有用,您几乎不能称之为bug).当我在最近的一篇帖子上看到
PROMPT_COMMAND
时,我想起了这个问题,然后又回到了它,但似乎这个想法已经给出了。我还认为bash实际上可能是在用
\[
\]
生成字符,并试图对其进行检查,但
ttyrec
的输出令人困惑,所以我放弃了+1顺便说一句,听起来很公平,但不起作用。chepner已经描述了在调用外部命令之前如何进行转义。
prompt_cmd () {
    PS1="$(green_cheese.sh)"
    PS1+=' \$ '
}

PROMPT_COMMAND=prompt_cmd
function readline_ANSI_escape() {
  if [[ $# -ge 1 ]]; then
    echo "$*"
  else
    cat  # Read string from STDIN
  fi | \
  perl -pe 's/(?:(?<!\x1)|(?<!\\\[))(\x1b\[[0-9;]*[mG])(?!\x2|\\\])/\x1\1\x2/g'
}
$ echo $'\e[0;1;31mRED' | readline_ANSI_escape
$ readline_ANSI_escape "$string"