Bash fish shell:仅当存在以前的输出时,才在提示前添加换行符

Bash fish shell:仅当存在以前的输出时,才在提示前添加换行符,bash,terminal,fish,Bash,Terminal,Fish,(免责声明:我正在使用fish,但这同样适用于bash) 我当前的shell在提示符前打印一个换行符,以便在命令输出之间轻松找到它 # [...] echo # newline before prompt echo -s $arrow ' ' $cwd $git_info echo -n -s '❯ ' 但是,当没有以前的输出时,也会打印换行符,例如,在用printf“\033c”清除终端后(或当终端首次打开时): 编辑:后期编辑更便于携带 下面是我在bash中的实现方式: \uuuu提示符\

(免责声明:我正在使用fish,但这同样适用于bash)
我当前的shell在提示符前打印一个换行符,以便在命令输出之间轻松找到它

# [...]
echo # newline before prompt
echo -s $arrow ' ' $cwd $git_info
echo -n -s '❯ '
但是,当没有以前的输出时,也会打印换行符,例如,在用
printf“\033c”
清除终端后(或当终端首次打开时):


编辑:后期编辑更便于携带

下面是我在bash中的实现方式:

\uuuu提示符\u换行符=$'\nvv'
__设置\u缺少\u换行\u修复()
{
本地CURPOS
echo-en“\033[6n”#ANSI DSR
读取-s-d-R CURPOS
CURPOS=${CURPOS}
如果[$CURPOS-等式1];则
__缺少\u新行\u FIX=“”
其他的
__缺少\u换行符\u修复=“$\u提示\u换行符”
fi
}
PROMPT\u命令=\uuuuuu集合\u缺少\u换行\u修复
PS1=“\${uu缺少新行\u修复}\w>”
注意,它被配置为在提示符前加上
VVV
,让我知道最后一个命令没有以换行结束

演示:

施蒂克:

将导致终端将其当前光标位置写入为输入。由于我们是一个交互式shell,该输入可用于shell的stdin,因此我们只需
读取-s
它(无回声)

在上面的链接中,您将看到响应的形式是
CSI Pl;Pc R
,因此我们告诉
read
读取并包括
R
-dr

然后我们使用bash的“remove matching prefix”语法
${CURPOS#*}
提取
Pc
部分,该语法删除分号
之前的所有内容

然后,如果光标位置不是1,也就是说,我们不在换行符的开头,我们将手动向提示中添加一个换行符

ANSI DSR应适用于所有与ANSI兼容的终端,但如果您遵循链接,您将看到它并不是字面上说的
\033[6n
,而是说
CSI 6 n
。是。转义序列以ASCII 27 ESC字符(八进制033)开始


在我最初的答案中,我使用了
\E
,bash内置的
echo-E
命令解析的内容与
\033
相同,因此上面进行了编辑。

我仍然希望我们可以使用类似于DSR签入root的答案,但fish可能不支持这一点

因此,我将根据我遇到的问题,提出一个非常非常规的解决方案(如果你觉得这很有用,也可以对答案进行投票)。如果您使用
tmux
,则可以通过其缓冲区访问终端内容。如果您不使用
tmux
,则希望此信息对将来搜索时遇到它的人有用

假设一个相当直接的提示(您的提示似乎是):

我们可以使用以下功能:

function fish_prompt
    if begin
        # If we're running in a tmux session
        command -q tmux
        and set --query TMUX
    end
        # capture the screen contents, reverse them so that the
        # last line is first, and remove any blank lines
        set capt (tmux capture-pane -p | tac | grep ".")
        if begin
            # if the last line doesn't look like it started with the prompt
            not string match -qre "^> " $capt[1]
            # and the last line wasn't just an empty prompt
            and not string match -q ">" $capt[1]
            # and we didn't just repaint the screen
            and not test (count $capt) -eq 0
        end
            # then add the newline
            echo
        end
    else
        echo
    end

    echo -s "--- First line of prompt ---"
    echo -s -n "> "
end
我们将
$capt
设置为当前屏幕上tmux窗格的内容,顺序颠倒,使最后一行位于顶部,并删除任何没有文本的行(因为tmux捕获到屏幕底部,而与当前行号无关)

如果在
$capt
中没有任何行,则我们处于“屏幕清除”状态,提示被绘制为屏幕上的第一行。您说过在这种情况下不需要换行符,因此只有在$capt不为空时才打印它

但我们真正的测试是看最后一行输出(
$capt[1]
)是否与“提示符”匹配。在这种情况下,它意味着从
开始。在这种情况下,我们也不打印换行符

但是还有一个拐角处的情况,这是一行,提示时没有输入任何内容(按Enter键时,行上没有任何内容)。您可能认为检查
会捕捉到这一点,但由于某些原因,fish显然会重新绘制空提示符,而不带尾随空格。因此,还需要检查仅包含
的行


当然,如果最后一行更复杂,这需要修改。检查
$capt[2]
可能更容易,因为它始终是前一个提示的第一行。

Stock fish已经处理了这个问题(并且已经多年了),不需要提示


当输出没有以换行符结尾时,您将看到“缺少换行符”,如“^1”或⏎", 后跟换行符,然后才是提示。

DSR行为是否取决于外壳、终端或操作系统?使用fish时,
echo-en”\E[6n“
只是得到字面上的回应。在bash中,它总是生成
;1R
,无论它是否是第一个命令。后编辑,但听起来你的终端没有正确报告,它是否也发生在其他终端上?另外,你如何测试它总是生成的内容?当位置不是1时,你需要发出DSR。”(验证…)并将其从终端读入类似于
hextump
的内容,以便响应中的第一个ESC不会被外壳或终端吞没。@Luis Beaucamp首先,fish
echo
等效为
echo-en”\e[6n”
。然而,一旦我们克服了这一点,我仍然有一个拦截器,fish的
读取
似乎无法处理这种情况。它的“静默”模式不会抑制,而是(从手册页)屏蔽写入终端的字符,用星号代替。这对于读取密码或其他敏感信息非常有用。"看起来bash的
read
在得到ANSI返回结果时会自动返回,而fish的则不会。我还没有解决这个问题。Oops-Missed@root的edit.\033对fish来说也是可移植的,并正确返回位置。不过,仍然没有解决
read
问题。请重新阅读o原始问题。这是关于创建cu的
$ source bashrc.sh
/tmp/so/newline > echo hello
hello
/tmp/so/newline > echo -n hello
hello
VVV /tmp/so/newline > 
--- First line of prompt ---
> 
function fish_prompt
    if begin
        # If we're running in a tmux session
        command -q tmux
        and set --query TMUX
    end
        # capture the screen contents, reverse them so that the
        # last line is first, and remove any blank lines
        set capt (tmux capture-pane -p | tac | grep ".")
        if begin
            # if the last line doesn't look like it started with the prompt
            not string match -qre "^> " $capt[1]
            # and the last line wasn't just an empty prompt
            and not string match -q ">" $capt[1]
            # and we didn't just repaint the screen
            and not test (count $capt) -eq 0
        end
            # then add the newline
            echo
        end
    else
        echo
    end

    echo -s "--- First line of prompt ---"
    echo -s -n "> "
end