这个问题毫无意义,但让我们开始吧!我正在 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
。 (也可以与$input
other 一起使用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:我讨厌这个解决方案,但它确实有效。