用DeepSeek写程序之一:编写在linux终端窗口右上角动态显示时间的c++程序

一. 简单需求

早前有个需求当SSH进入linux时,希望在终端窗口动太显示当前的时间,原来是用脚本解决的

while sleep 1;do tput sc;tput cup 0 $(($(tput cols)-29));date;tput rc;done & 

如果想加上颜色,改为:

while sleep 1;do tput sc;tput cup 0 $(($(tput cols)-8)); tput setb 1;tput setf 7;date  "+%T";tput rc;done & 

如果希望每次打开终端都能显示时间,而不必每次在控制台执行脚本,可以将其放在.bashrc中,即:

echo "while sleep 1;do tput sc;tput cup 0 $(($(tput cols)-29));date;tput rc;done &" >> $HOME/.bashrc 

实际使用时发现这种输出方式会影响窗口滚动,就是脚本输出时间时将窗口滚回最下方,影响相当大。
最近DeepSeek爆火后,看看DeepSeek能不能写个C++程序,同时解决窗口滚动问题。

二. 用DeepSeek写程序

向DeepSeek发出灵魂拷贝:“用c++编写程序,用于在linux用终端窗口右上角位置动态显示时间”,勾选“尝试思考(R1)”后,DeepSeek用时47秒洋洋洒洒的输出了一堆内容,用循环每隔一秒更新一次,用ANSI转义码33[<行>;<列>H把光标移动到终端右上角输出时间;要注意时间长度变会有短残留字符的问题;要处理终端的resize事件检测新的宽度;以及隐藏光标用33[?25l、恢复用33[?25h等。
最后给出一段C++代码:

#include <iostream> #include <chrono> #include <ctime> #include <iomanip> #include <unistd.h> #include <sys/ioctl.h> #include <csignal> #include <atomic> #include <string>  using namespace std::chrono_literals;  std::atomic_bool keep_running(true);  // 信号处理函数 void signal_handler(int signal) {     if (signal == SIGINT) {         keep_running = false;     } }  // 获取终端宽度 int get_terminal_width() {     struct winsize size{};     ioctl(STDOUT_FILENO, TIOCGWINSZ, &size);     return size.ws_col; }  // 隐藏光标 void hide_cursor() {     std::cout << "33[?25l"; }  // 显示光标 void show_cursor() {     std::cout << "33[?25h"; }  int main() {     // 注册信号处理     std::signal(SIGINT, signal_handler);          // 隐藏光标     hide_cursor();      while (keep_running) {         // 获取当前时间         auto now = std::chrono::system_clock::now();         std::time_t now_time = std::chrono::system_clock::to_time_t(now);         std::tm* local_time = std::localtime(&now_time);         std::string time_str = std::to_string(local_time->tm_hour) + ":"                               + std::to_string(local_time->tm_min) + ":"                               + std::to_string(local_time->tm_sec);          // 获取终端宽度并计算位置         int term_width = get_terminal_width();         int time_len = time_str.length();         int pos = term_width - time_len;          // 使用ANSI转义码移动光标并输出时间         std::cout << "33[1;" << pos << "H"  // 移动到第一行右侧                   << time_str                   << std::flush;          // 每秒更新一次         std::this_thread::sleep_for(1s);     }      // 清理并恢复光标     std::cout << "33[2K33[1;1H";  // 清除第一行并移动光标到左上角     show_cursor();     std::cout << std::flush;      return 0; } 

瞅了一眼,应该没处理好滚动问题,再追加一个要求:“要求程序在后台运行,不影响用户输入命令”,DeepSeek深度思考60秒后再次给出一段代码:

#include <iostream> #include <chrono> #include <ctime> #include <iomanip> #include <unistd.h> #include <sys/ioctl.h> #include <csignal> #include <atomic> #include <string>  using namespace std::chrono_literals;  std::atomic_bool keep_running(true);  void signal_handler(int signal) {     if (signal == SIGINT) {         keep_running = false;     } }  int get_terminal_width() {     struct winsize size{};     ioctl(STDOUT_FILENO, TIOCGWINSZ, &size);     return size.ws_col; }  void hide_cursor() {     std::cout << "33[?25l"; }  void show_cursor() {     std::cout << "33[?25h"; }  int main() {     std::signal(SIGINT, signal_handler);     hide_cursor();      while (keep_running) {         auto now = std::chrono::system_clock::now();         std::time_t now_time = std::chrono::system_clock::to_time_t(now);         std::tm* local_time = std::localtime(&now_time);                  // 格式化时间(修复个位数显示问题)         std::stringstream ss;         ss << std::setw(2) << std::setfill('0') << local_time->tm_hour << ":"            << std::setw(2) << std::setfill('0') << local_time->tm_min << ":"            << std::setw(2) << std::setfill('0') << local_time->tm_sec;         std::string time_str = ss.str();          int term_width = get_terminal_width();         int time_len = time_str.length();         int pos = term_width - time_len;          // 关键修改:保存光标位置 -> 输出时间 -> 恢复光标位置         std::cout << "33[s"                   // 保存光标位置                   << "33[1;" << pos << "H"     // 移动到右上角                   << time_str                   << "33[u"                    // 恢复光标位置                   << std::flush;          std::this_thread::sleep_for(1s);     }      // 退出时清除时间显示     std::cout << "33[s33[1;" << (get_terminal_width() - 8) << "H33[0K33[u";     show_cursor();     std::cout << std::flush;      return 0; } 

而且强调:

每次输出时间时,将光标移动到右上角,输出时间后立即将光标移回原来的位置,这样用户输入的命令不会被打断。例如,当用户在输入命令时,程序在后台每隔一秒将光标移到右上角,写入时间,然后移回原来的位置,这样用户的输入不会被覆盖。
这可能需要记录光标的当前位置,在输出时间后恢复。例如,使用ANSI转义码保存光标位置,移动输出时间,然后恢复。例如:

  • 保存光标位置:33[s
  • 移动光标到右上角:33[1;H
  • 输出时间
  • 恢复光标位置:33[u
    这样,用户在输入时,每次更新时间时,程序会保存当前光标位置,输出时间到右上角,然后恢复,这样用户的输入不会被干扰。

好吧,看样子它并没有理解我说的内容。还是先试试代码能不能运行。

三. 编译运行

DeekSeek给出运行方式:

# 编译程序 g++ -o clock clock.cpp -std=c++11 -lpthread  # 后台运行(推荐方式) ./clock &  # 完全脱离终端运行(关闭终端后仍然有效) nohup ./clock > /dev/null 2>&1 & 

毫无意外,报错了。
用DeepSeek写程序之一:编写在linux终端窗口右上角动态显示时间的c++程序

改用c++14来编译:
g++ -o clock clock.cpp -std=c++14 -lpthread
再次报错:
用DeepSeek写程序之一:编写在linux终端窗口右上角动态显示时间的c++程序

咱自己改一改,加上#include <thread>后编译成功,运行clock直接输出当前时间,运行./clock & 实现在窗口右上角动态显示当前时间。
用DeepSeek写程序之一:编写在linux终端窗口右上角动态显示时间的c++程序

但是和脚本实现一样,会影响窗口滚动。要求DeepSeek再改进,反复出现“服务器繁忙,请稍后再试。”,没法进行只能放弃。

四. 总结

DeepSeek基本能按要求写出似模似样的代码,有些小问题修正后能够使用。

以上测试环境:Linux openEuler1 5.10.0-229.0.0.128.oe2203sp4.x86_64 #1 SMP Wed Sep 18 16:21:54 CST 2024 x86_64 x86_64 x86_64 GNU/Linux,SSH工具:PuTTY Release 0.72。

发表评论

评论已关闭。

相关文章