Bash 函数似乎不想正确运行行

Bash 函数似乎不想正确运行行

这个问题毫无意义,但让我们开始吧!我正在 bash 中开发 IRC 客户端,我找到了一些代码并开始将其添加到我一直在开发的 IRC bash 机器人代码中。我已将其分解以简化它。 GNU bash,版本 4.3.48(1)-发布

#!/bin/bash
#!/user/bin/perl

function status_line() {
    echo -en '\e7' "\e[${status_line_row};0f" '\e[2K'
    echo -en "\e[4;44mSTATUS: $nick in $channel @ $channel\e[0m"
    echo -en '\e8'
}

function read_line() {
while true
do
    while read -r -t1
    do 
        status_line
        echo -en '\e[2K\r> '
        echo "PRIVMSG $channel :$REPLY" >> $input   
    done
done
}

. bot.properties
input=".bot.cfg"
echo "Starting session: $(date "+[%y:%m:%d %T]")">$log 
echo "NICK $nick" > $input 
echo "USER $user" >> $input
echo "JOIN $channel" >> $input

read_line | tail -f $input | openssl s_client -connect $server:6697 

运行此命令并在终端中输入输入后,它会正确输入并将 $REPLY 发送到 IRC,但它无法正确执行 read_line 内的 status_line 和 echo -en '\e[2K\r> ' 。我很困惑为什么正在读取输入但它之前的两行不起作用。在向 IRC 发送一条消息后,我对其运行 bash -x 来查看这一点(如下),如果没有 -x,这甚至无法修复它。

+ status_line
+ echo -en '\e7' '\e[;0f' '\e[2K'
+ echo -en '\e[4;44mSTATUS: Omen in #lair @ #lair\e[0m'
+ echo -en '\e8'
+ echo -en '\e[2K\r> '
+ read -r -t1
+ true

如果您想查看完整代码,请点击此处>https://pastebin.com/cHLiwZNf

答案1

function read_line() {
    ...
    while read -r -t1; do
        status_line
        echo -en '\e[2K\r> '
        echo "PRIVMSG $channel :$REPLY" >> $input   
    ...
}

read_line | tail ...

它无法在 read_line 中正确执行 status_line 和 echo -en '\e[2K\r> ' 。我很困惑为什么正在读取输入但它之前的两行不起作用。

在内部read_line,您可以使用 读取标准输入read,然后使用 打印到标准输出echo。 (也可以与$inputother 一起使用echo,但这不是问题。)

注意您如何将read_line函数作为管道的一部分进行调用,考虑一下 stdin 和 stdoutread_line连接在哪里?管道对所涉及命令的输入和输出流做了什么?tail它对其 stdin 做了什么?


另请注意,如果这>应该是对用户的提示,则可能应该将其打印出来呼叫read,而不是之后。要么执行while echo -en '\e[2K\r> '; read -r -t1; do ...,要么使用read -p让它打印提示。如果终端以通常的方式设置,当用户在 上按回车键read以及打印某些内容时,屏幕也会滚动。如果状态栏位于屏幕顶部,它将滚动到看不见的地方。您必须对此采取一些措施,并且使用预先存在的 UI 库(例如ncurses在 shell 中手动修复终端处理)要容易得多。

IRC 客户端的另一个问题是需要能够同时从两个地方读取:来自用户的输入和来自网络的数据。将输出修复openssl回脚本进行处理本身就有些尴尬,并且必须同时读取两者更糟糕。

真正的解决方案是使用系统select()调用(或者poll())。尽管 Bash 通过/dev/tcp伪文件提供了对网络套接字的访问,但我不认为它提供了select().

所以,实际上,有两个重要的原因需要使用实际的编程语言不是外壳为了这。

当然,如果您只是将其作为一种疯狂的练习,那么也没有问题,但如果是这样,我建议您在解决此类问题之前先稍微熟悉一下 shell 语言。另外,如果你只是想在有限的环境中享受编程的乐趣,而没有任何现实意义,我可以推荐一些来自扎克电子公司为了那个原因。

答案2

感谢@Kusalananda,他们的答案让我进行了搜索,我找到了答案。如果他们给出的答案是正确的,再次感谢,抱歉哈哈!无论如何,>&2在行尾添加我想打印到终端!仍在使用它并使其适合我的情况,但它有效!

function read_line() {
while true
do
    while read -r -t1 REPLY
    do 
        echo 'Hello World' >&2
        echo -en '\e[2K\r> ' >&2
        echo "PRIVMSG $channel :$REPLY" >> $input   
    done
done
}

答案3

首先,这里有很多东西需要解压。如果您还没有开始使用外壳检查,那么您应该开始 - 它通过突出显示写入时的缺陷使生活变得更加轻松。

其次,shell 不喜欢这一行:echo -en '\e7' "\e[${status_line_row};0f" '\e[2K'。我不确定它应该做什么,但它会导致光标向上跳一行并写入一个空白(?);那不可能是你想要的。首先解决这个问题。

接下来,在该块的上下文中,该while true位似乎您不需要它。

function read_line() {
while true; do <- unnecessary
    while read -r -t1
    do 
        status_line
        echo -en '\e[2K\r> '
        echo "PRIVMSG $channel :$REPLY" >> $input   
    done
done <- unnecessary
}

# This should do exactly the same thing but you have to feed the loop
while read -r -t1; do 
    status_line
    echo -en '\e[2K\r> '
    echo "PRIVMSG $channel :$REPLY" >> $input   
done < /from/file, or
done <<< "$fromVariable" (pick one from file or variable)

最后,这里有一个要旨这应该有助于概述如何更轻松地对输出进行着色。我将其称为库并在多个脚本上重用。 PS:我讨厌这个解决方案,但它确实有效。

相关内容