如何在提示符后自动插入字符串

如何在提示符后自动插入字符串

我有一个bash终端窗口,我可以在其中执行一声令下foo。因此,我希望每一行(当然在提示之后)都以“foo”开头,这样我只需键入函数的选项和参数,而不是重复的函数名称。当然,如果能够更改自动插入的字符串就好了,但这就是不是必需的为我。

例子

当我打开终端时,无需输入任何内容,我想看到的是:

user@host:~/ $ foo 

然后我键入--option argument,当我按下时,将使用给定的和调用Enter该函数。foo--optionargument

我尝试过的

我尝试摆弄$PS1$PROMPT_COMMAND使用xdotool type "foo ",令人惊讶的是它实际上有效,但不幸的是它也打印“foo”提示符非常难看:

user@host:~/ $ PROMPT_COMMAND='xdotool type "foo "'
foo user@host:~/ $ foo 

我还发现并尝试了该preexec功能Ryan Caloras 的 bash-preexec 脚本,但它有完全相同的问题。

如何回显(a(executable-)string)到提示符,以便光标在行尾闪烁?是相关的,但是那里的答案无法将某些内容(--option argument)添加到要执行的命令中。不过我没有测试过——这么简单的事情zsh应该有一个解决方案,你不觉得吗?bash

答案1

对于zsh,它应该只是一个问题:

precmd() print -z 'foo '

或者避免它覆盖用户排队的命令Alt+q

zle-line-init() { [ -n "$BUFFER" ] || LBUFFER='foo '; }
zle -N zle-line-init

使用bash, 代替xdotool,您可以使用TIOCSTI ioctl

insert() {
  perl -le 'require "sys/ioctl.ph";
            ioctl(STDIN, &TIOCSTI, $_) for split "", join " ", @ARGV' -- "$@"
}
PROMPT_COMMAND='insert "foo "'

这是更可取的,xdotool因为它将这些字符直接插入到bash正在读取的设备的输入缓冲区中。仅当有一台 X 服务器正在运行时才起作用(例如,在控制台或真实终端上或在(没有)xdotool上不起作用),它是由 标识的服务器,并且是您正在与之交互的服务器,并且终端正在运行的模拟器在评估时具有焦点。ssh-X$DISPLAYbash$PROMPT_COMMAND

现在,就像您的xdotool情况一样,因为这ioctl()是在显示提示之前完成的,并且 tty 终端线路规则被 readline 退出icanon+echo模式,您可能会看到回声其中footty 线路规则弄乱了显示。

您可以通过插入一个字符串来解决这个问题回声是不可见的(如果仅使用 Unicode 语言环境,则类似于 U+200B)并将其绑定到插入的操作"foo "

insert() {
  perl -le 'require "sys/ioctl.ph";
            ioctl(STDIN, &TIOCSTI, $_) for split "", join " ", @ARGV' -- "$@"
}
bind $'"\u200b":"foo "'
PROMPT_COMMAND="insert $'\u200b'"

或者您可以延迟TIOCSTIioctl 足够长的时间,以便 readline 有时间初始化:

insert_with_delay() {
  perl -le 'require "sys/ioctl.ph";
            $delay = shift @ARGV;
            unless(fork) {
              select undef, undef, undef, $delay;
              ioctl(STDIN, &TIOCSTI, $_) for split "", join " ", @ARGV;
            }' -- "$@";
}
PROMPT_COMMAND='insert_with_delay 0.05 "foo "'

如果像方法中一样zsh,您想要处理用户在显示提示之前输入文本的情况,您可以

  • 流走通过tcflush(0, TCIFLUSH)在ioctlperl之前执行 a TIOCSTI(也需要一个-MPOSIX选项),或者
  • 就像在该zsh方法中一样,通过在(移动到末尾)之前和之后插入(假设您使用(默认)编辑模式,将光标移动到行的开头) ,确保foo在缓冲区的开头插入:^Aemacsfoo^E

    insert_with_delay 0.05 $'\1foo \5'
    

    或者

    bind $'"\u200b":"\1foo \5"'
    

答案2

您所要求的听起来并不常见,因此没有一种简单的方法来做到这一点也就不足为奇了。

使用纯 bash,您可以使用read内置函数读取该行,然后eval执行它。模拟提示(我在下面近似您的提示)。

#!/bin/bash    
PROMPT=$'\e[1m'$USER@$HOSTNAME:$PWD$' $ \e[0m'
IFS= read -r -e -i "foo " -p "$PROMPT" line
eval "$line"
exit

将其放入脚本中并告诉您的终端模拟器运行该脚本。

或者,在终端模拟器中运行 Screen。您可以使用它的stuff命令来模拟输入。

相关内容