Redian新闻
>
使用 dialog 和 jq 在 Linux 上编写高效终端 TUI | Linux 中国

使用 dialog 和 jq 在 Linux 上编写高效终端 TUI | Linux 中国

科技
 
导读:许多人每日都在使用终端,因此,文字用户界面(TUI)逐渐显示出其价值。                   
本文字数:7052,阅读时长大约:8分钟

https://linux.cn/article-16391-1.html
作者:Jose Nunez
译者:ChatGPT

为何选择文字用户界面(TUI)?

许多人每日都在使用终端,因此,文字用户界面(Text User Interface)(TUI)逐渐显示出其价值。它能减少用户输入命令时的误差,让终端操作更高效,提高生产力。

以我的个人使用情况为例:我每日会通过家用电脑远程连接到我使用 Linux 系统的实体 PC。所有的远程网络连接都通过私有 VPN 加密保护。然而,当我需要频繁重复输入命令进行连接时,这种经历实在令人烦躁。

于是,我创建了下面这个 Bash 函数,从而有所改进:

  1. export REMOTE_RDP_USER="myremoteuser"
  2. function remote_machine() {
  3. /usr/bin/xfreerdp /cert-ignore /sound:sys:alsa /f /u:$REMOTE_RDP_USER /v:$1 /p:$2
  4. }

但后来,我发现自己还是频繁地执行下面这条命令(在一行中):

  1. remote_pass=(/bin/cat/.mypassfile) remote_machine $remote_machine $remote_pass

这太烦了。更糟糕的是,我的密码被明文存储在我的电脑上(我虽然使用了加密驱动器,但这点依然令人不安)。

因此,我决定投入一些时间,编写一个实用的脚本,从而更好地满足我的基本需求。

我需要哪些信息才能连接到远程桌面?

实际上,要连接到远程桌面,你只需提供少量信息。这些信息需要进行结构化处理,所以一个简单的 JSON 文件就能够满足要求:

  1. {"machines": [
  2. {
  3. "name": "machine1.domain.com",
  4. "description": "Personal-PC"
  5. },
  6. {
  7. "name": "machine2.domain.com",
  8. "description": "Virtual-Machine"
  9. }
  10. ],
  11. "remote_user": "MYUSER@DOMAIN",
  12. "title" : "MY COMPANY RDP connection"
  13. }

尽管在各种配置文件格式中,JSON 并非最佳选择(例如,它不支持注解),但是 Linux 提供了许多工具通过命令行方式解析 JSON 内容。其中,特别值得一提的工具就是 jqstedolan.github.io。下面我要向你展示如何利用它来提取机器列表:

  1. /usr/bin/jq --compact-output --raw-output '.machines[]| .name' \
  2. $HOME/.config/scripts/kodegeek_rdp.json) \
  3. "machine1.domain.com" "machine2.domain.com"

jq 的文档可以在 这里jqlang.github.io 找到。另外,你也可以直接将你的 JSON 文件复制粘贴到 jq playjqplay.org,试用你的表达式,然后在你的脚本中使用这些表达式。

既然已经准备好了连接远程计算机所需的所有信息,那现在就让我们来创建一个美观实用的 TUI 吧。

Dialog 的帮助

Dialoginvisible-island.net 是那些你可能希望早些认识的、被低评估的 Linux 工具之一。你可以利用它构建出一个井然有序、简介易懂,并且完美适用于你终端的用户界面。

比如,我可以创建一个包含我喜欢的编程语言的简单的复选框列表,且默认选择 Python:

  1. dialog --clear --checklist "Favorite programming languages:" 10 30 7\
  2. 1 Python on 2 Java off 3 Bash off 4 Perl off 5 Ruby off

我们通过这条命令向 dialog 下达了几个指令:

◈ 清除屏幕(所有选项都以 -- 开头)
◈ 创建一个带有标题的复选框(第一个位置参数)
◈ 决定窗口尺寸(高度、宽度和列表高度,共 3 个参数)
◈ 列表中的每条选项都由一个标签和一个值组成。

惊人的是,仅仅一行代码,就带来了简洁直观和视觉友好的选择列表。

关于 dialog 的详细文档,你可以在 这里invisible-island.net 阅读。

整合所有元素:使用 Dialog 和 JQ 编写 TUI

我编写了一个 TUI,它使用 jq 从我的 JSON 文件中提取配置详细信息,并且使用 dialog 来组织流程。每次运行,我都会要求输入密码,并将其保存在一个临时文件中,脚本使用后便会删除这个临时文件。

这个脚本非常基础,但它更安全,也使我能够专注于更重要的任务 🙂

那么 脚本raw.githubusercontent.com 看起来是怎样的呢?下面是代码:

  1. #!/bin/bash
  2. # Author Jose Vicente Nunez
  3. # Do not use this script on a public computer. It is not secure...
  4. # https://invisible-island.net/dialog/
  5. # Below some constants to make it easier to handle Dialog
  6. # return codes
  7. : ${DIALOG_OK=0}
  8. : ${DIALOG_CANCEL=1}
  9. : ${DIALOG_HELP=2}
  10. : ${DIALOG_EXTRA=3}
  11. : ${DIALOG_ITEM_HELP=4}
  12. : ${DIALOG_ESC=255}
  13. # Temporary file to store sensitive data. Use a 'trap' to remove
  14. # at the end of the script or if it gets interrupted
  15. declare tmp_file=$(/usr/bin/mktemp 2>/dev/null) || declare tmp_file=/tmp/test$$
  16. trap "/bin/rm -f $tmp_file" QUIT EXIT INT
  17. /bin/chmod go-wrx ${tmp_file} > /dev/null 2>&1
  18. :<<DOC
  19. Extract details like title, remote user and machines using jq from the JSON file
  20. Use a subshell for the machine list
  21. DOC
  22. declare TITLE=$(/usr/bin/jq --compact-output --raw-output '.title' $HOME/.config/scripts/kodegeek_rdp.json)|| exit 100
  23. declare REMOTE_USER=$(/usr/bin/jq --compact-output --raw-output '.remote_user' $HOME/.config/scripts/kodegeek_rdp.json)|| exit 100
  24. declare MACHINES=$(
  25. declare tmp_file2=$(/usr/bin/mktemp 2>/dev/null) || declare tmp_file2=/tmp/test$$
  26. # trap "/bin/rm -f $tmp_file2" 0 1 2 5 15 EXIT INT
  27. declare -a MACHINE_INFO=$(/usr/bin/jq --compact-output --raw-output '.machines[]| join(",")' $HOME/.config/scripts/kodegeek_rdp.json > $tmp_file2)
  28. declare -i i=0
  29. while read line; do
  30. declare machine=$(echo $line| /usr/bin/cut -d',' -f1)
  31. declare desc=$(echo $line| /usr/bin/cut -d',' -f2)
  32. declare toggle=off
  33. if [ $i -eq 0 ]; then
  34. toggle=on
  35. ((i=i+1))
  36. fi
  37. echo $machine $desc $toggle
  38. done < $tmp_file2
  39. /bin/cp /dev/null $tmp_file2
  40. ) || exit 100
  41. # Create a dialog with a radio list and let the user select the
  42. # remote machine
  43. /usr/bin/dialog \
  44. --clear \
  45. --title "$TITLE" \
  46. --radiolist "Which machine do you want to use?" 20 61 2 \
  47. $MACHINES 2> ${tmp_file}
  48. return_value=$?
  49. # Handle the return codes from the machine selection in the
  50. # previous step
  51. export remote_machine=""
  52. case $return_value in
  53. $DIALOG_OK)
  54. export remote_machine=$(/bin/cat ${tmp_file})
  55. ;;
  56. $DIALOG_CANCEL)
  57. echo "Cancel pressed.";;
  58. $DIALOG_HELP)
  59. echo "Help pressed.";;
  60. $DIALOG_EXTRA)
  61. echo "Extra button pressed.";;
  62. $DIALOG_ITEM_HELP)
  63. echo "Item-help button pressed.";;
  64. $DIALOG_ESC)
  65. if test -s $tmp_file ; then
  66. /bin/rm -f $tmp_file
  67. else
  68. echo "ESC pressed."
  69. fi
  70. ;;
  71. esac
  72. # No machine selected? No service ...
  73. if [ -z "${remote_machine}" ]; then
  74. /usr/bin/dialog \
  75. --clear \
  76. --title "Error, no machine selected?" --clear "$@" \
  77. --msgbox "No machine was selected!. Will exit now..." 15 30
  78. exit 100
  79. fi
  80. # Send 4 packets to the remote machine. I assume your network
  81. # administration allows ICMP packets
  82. # If there is an error show message box
  83. /bin/ping -c 4 ${remote_machine} >/dev/null 2>&1
  84. if [ $? -ne 0 ]; then
  85. /usr/bin/dialog \
  86. --clear \
  87. --title "VPN issues or machine is off?" --clear "$@" \
  88. --msgbox "Could not ping ${remote_machine}. Time to troubleshoot..." 15 50
  89. exit 100
  90. fi
  91. # Remote machine is visible, ask for credentials and handle user
  92. # choices (like password with a password box)
  93. /bin/rm -f ${tmp_file}
  94. /usr/bin/dialog \
  95. --title "$TITLE" \
  96. --clear \
  97. --insecure \
  98. --passwordbox "Please enter your Windows password for ${remote_machine}\n" 16 51 2> $tmp_file
  99. return_value=$?
  100. case $return_value in
  101. $DIALOG_OK)
  102. # We have all the information, try to connect using RDP protocol
  103. /usr/bin/mkdir -p -v $HOME/logs
  104. /usr/bin/xfreerdp /cert-ignore /sound:sys:alsa /f /u:$REMOTE_USER /v:${remote_machine} /p:$(/bin/cat ${tmp_file})| \
  105. /usr/bin/tee $HOME/logs/$(/usr/bin/basename $0)-$remote_machine.log
  106. ;;
  107. $DIALOG_CANCEL)
  108. echo "Cancel pressed.";;
  109. $DIALOG_HELP)
  110. echo "Help pressed.";;
  111. $DIALOG_EXTRA)
  112. echo "Extra button pressed.";;
  113. $DIALOG_ITEM_HELP)
  114. echo "Item-help button pressed.";;
  115. $DIALOG_ESC)
  116. if test -s $tmp_file ; then
  117. /bin/rm -f $tmp_file
  118. else
  119. echo "ESC pressed."
  120. fi
  121. ;;
  122. esac

你从代码中可以看出,dialog 预期的是位置参数,并且允许你在变量中捕获用户的回应。这实际上使其成为编写文本用户界面的 Bash 扩展。

上述的小例子只涵盖了一些部件的使用,其实还有更多的文档在 官方 dialog 网站invisible-island.net上。

Dialog 和 JQ 是最好的选择吗?

实现这个功能可以有很多方法(如 Textualtextual.textualize.io,Gnome 的 Zenitygitlab.gnome.org,Python 的 TKinkerdocs.python.org等)。我只是想向你展示一种高效的方式——仅用 100 行代码就完成了这项任务。

确实,它并不完美。更具体地讲,它与 Bash 的深度集成使得代码有些冗长,但仍然保持了易于调试和维护的特性。相比于反复复制粘贴长长的命令,这无疑是一个更好的选择。

最后,如果你喜欢在 Bash 中使用 jq 处理 JSON,那么你会对这个 jq 配方的精彩集合nntrn.github.io 感兴趣的。

(题图:MJ/a9b7f60a-02ec-4d3f-88ae-2321f49ac0e1)


via: https://fedoramagazine.org/writing-useful-terminal-tui-on-linux-with-dialog-and-jq/

作者:Jose Nunez 选题:lujun9972 译者:ChatGPT 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

欢迎遵照 CC-BY-SA 协议规定转载,
如需转载,请在文章下留言 “转载:公众号名称”,
我们将为您添加白名单,授权“转载文章时可以修改”。


微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
【天与湖】 一组小诗Vojtux:针对视力障碍用户改造 Linux | Linux 中国Ubuntu 与 Kubuntu:哪一个更适合你? | Linux 中国使用 Btrfs 快照方便升级 Fedora Linux 且易于回退 | Linux 中国PeerTube 发布第 6 版,获得比 YouTube 更好的功能 | Linux 中国首款 Linux 游戏本?!Tuxedo 推出 Linux 游戏本 Sirius 16彭博终端有妙招 | 彭博终端PM <GO>:高效完成投组再平衡(实操视频)Vlog不读“veelog”,KWAS不读“靠斯”,这些易读错的单词你念对了吗?Ubuntu Studio 23.10:致力于简化音频制作 | Linux 中国我在网上编故事,月入十几万咏球道珊瑚树在 Linux 终端利用 Asciiquarium 打造海底世界 | Linux 中国Linux 黑话解释:Linux 中的 Super 键是什么? | Linux 中国硬核观察 #1177 大多数使用 jQuery 的网站都运行着不再维护的版本我国首例终端到终端低轨卫星通信测试成功;新疆自贸试验区总体方案公布丨科技早新闻AI与诗词创作Linux 中的 ls 命令使用教程 | Linux 中国jQuery 4.0,开发进度已完成 99%终端基础:在 Linux 中重命名文件和目录 | Linux 中国10 个在 Linux 终端中生成有趣的 ASCII 字符画的工具 | Linux 中国Wave:即使你讨厌命令行,也会喜欢的现代新 Linux 终端 | Linux 中国Garuda Linux “Spizaetus” 发布,可以体验 KDE Plasma 6 了! | Linux 中国娄岩一周诗词五首火遍童年的 FC 游戏是使用什么语言编写的彭博终端有妙招 | 彭博终端IN <GO>:覆盖各大资产类别,助您把握机遇!(实操视频)Linus Torvalds:Linux 内核中的 Rust、AI 和疲劳的维护者 | Linux 中国终端基础:Linux 终端中的目录切换 | Linux 中国在 Linux 的 VirtualBox 中从 USB 驱动器启动 | Linux 中国欧阳娜娜的Vlog不读“veelog”,KWAS不读“靠斯”,这些易读错的单词你念对了吗?在 Ubuntu 等非 Nix 操作系统上安装和使用 Nix 包管理器 | Linux 中国在 Arch Linux 上安装和使用 Yay | Linux 中国《九月,2023》《September, 2023》在线编写和运行Python代码 使用介绍Textual:为 Python 增加漂亮的文本用户界面(TUI) | Linux 中国备受欢迎的数字音频工作站 Studio One 新增了对 Linux 的支持 | Linux 中国
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。