2022-04-23 23:25:25 星期六
本工具的详细开发步骤请参见《开发篇:Linux下的swing窗体程序开发》。
开发环境:Windows 10
开发工具:IntelliJ IDEA
测试环境:银河麒麟 V10
尽管用户管理工具的开发刚开始不久,但我觉得有必要先写下这篇博客,记录一下在此过程中遇到的 bug,并为以后处理此类错误提供一点启发。进行开发之前我在脑海里构思了一遍大概的设计流程。先做一个主窗体,然后做四个功能按钮,点击四个按钮再打开四个带有不同功能模块的子窗体,在子窗体里设计一个显示域,几个可供点击的功能按钮,然后为这几个按钮写入相应的 Linux 命令,通过 getRuntime()
放到 Linux 下执行,然后把结果取回来,输出到显示域中就可以了,不就依法炮制四个窗体嘛。
梦开始的地方···
设想是如此美好,可现实是刚刚起步就很快体会到了用 Java 做窗体开发的痛苦,我本来是打算在 Qt 下进行本次开发的,奈何 Qt 确实不会用,倒不如选择自己熟悉的 IDE。因为我考虑到,Qt 主要是提供给 C++ 开发者使用的,使用 Java 做 Qt 开发的不多,尤其是我几乎不能在网上找到有关在 Qt 上做 Java 开发的教程,这意味着如果使用 Qt 做 Java 开发的话,我不仅要完全凭感觉去进行 Java 开发,最可怕的是,如果在开发过程中遇到一些“变态”的 bug,在没有前例的情况下,我很可能无法独立去解决它···综上所述,最终我选择了钟爱的 IntelliJ IDEA。
好几个小时过去了,我现在仍停留在开发这款工具的图形界面,我敢保证自己绝对没有偷懒,用原生代码来做图形界面开发简直令人发狂(虽然 IDEA 为 swing 提供了 GUI 插件 Swing UI Designer,可以实现一定程度的“所见即所得”,但使用起来很不方便,更多时候我宁可使用原生代码去调试),尤其是在经历过 Visual Studio 下的 C# 窗体开发后,swing 给人的落差感太大了。由于详细的开发历程已记录到另一篇文章,此处就不赘述了。
同一条指令,无数种反馈
在设计好基本的界面后,进入到本工具开发的最关键环节——与 Linux 系统做交互,也就是通过 Java 去执行 Linux 命令然后获取返回值。第一个功能是用户清单,即实现用户详细信息的输出,因为要读取用户信息,我选择读取 /etc/passwd 的每一行去得到每一个用户(这应该是大部分 Linux 开发者面对这个问题时想到的第一个解决方案)。这时候第一个 bug 来了,去读 passwd 的每一行,该用哪一条指令呢?这时候我条件反射地想起了 cat /etc/passwd,虽然这样把所有的用户都输出了,不能单独拿出每一行,但我并不在意这个问题,因为它很好解决,等拿到这包含全部用户信息的一整个字符串后,我在程序里处理这个字符串,分割出每一个用户就好了,平时编程的时候也经常这样处理字符串。意想不到的是,cat /etc/passwd 返回的数据在 Linux 下明明是保有换行的(passwd 中一个用户占一行),可是当把 cat 指令放到 Java 中执行后,返回的数据居然变成了杂糅在一起的一团!??所有的换行都消失了,我测试的40行数据全部输出到了同一行内并且没有任何分隔符!从这一刻起,在 Linux 终端下老老实实的指令开始在我的 Java 程序里作威作福!我执行的难道不是同一条指令么?
Linux 终端下的 cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
messagebus:x:101:101::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:102:102:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
systemd-network:x:103:104:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:104:105:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
tcpdump:x:105:110::/nonexistent:/usr/sbin/nologin
syslog:x:106:111::/home/syslog:/usr/sbin/nologin
avahi-autoipd:x:107:115:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/usr/sbin/nologin
dnsmasq:x:108:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
strongswan:x:109:65534::/var/lib/strongswan:/usr/sbin/nologin
cups-pk-helper:x:110:119:user for cups-pk-helper service,,,:/home/cups-pk-helper:/usr/sbin/nologin
lightdm:x:111:120:Light Display Manager:/var/lib/lightdm:/bin/false
sshd:x:112:65534::/run/sshd:/usr/sbin/nologin
xrdp:x:113:122::/run/xrdp:/usr/sbin/nologin
avahi:x:114:123:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/usr/sbin/nologin
pulse:x:115:125:PulseAudio daemon,,,:/var/run/pulse:/usr/sbin/nologin
saned:x:116:127::/var/lib/saned:/usr/sbin/nologin
hplip:x:117:7:HPLIP system user,,,:/run/hplip:/bin/false
nvidia-persistenced:x:118:128:NVIDIA Persistence Daemon,,,:/nonexistent:/usr/sbin/nologin
uuidd:x:119:130::/run/uuidd:/usr/sbin/nologin
yuanyi:x:1000:1000:yuanyi:/home/yuanyi:/bin/bash
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
Process 下的 cat /etc/passwd
root:x:0:0:root:/root:/bin/bashdaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologinbin:x:2:2:bin:/bin:/usr/sbin/nologinsys:x:3:3:sys:/dev:/usr/sbin/nologinsync:x:4:65534:sync:/bin:/bin/syncgames:x:5:60:games:/usr/games:/usr/sbin/nologinman:x:6:12:man:/var/cache/man:/usr/sbin/nologinlp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologinmail:x:8:8:mail:/var/mail:/usr/sbin/nologinnews:x:9:9:news:/var/spool/news:/usr/sbin/nologinuucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologinproxy:x:13:13:proxy:/bin:/usr/sbin/nologinwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologinbackup:x:34:34:backup:/var/backups:/usr/sbin/nologinlist:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologinirc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologingnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologinnobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin_apt:x:100:65534::/nonexistent:/usr/sbin/nologinmessagebus:x:101:101::/nonexistent:/usr/sbin/nologinsystemd-timesync:x:102:102:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologinsystemd-network:x:103:104:systemd Network Management,,,:/run/systemd:/usr/sbin/nologinsystemd-resolve:x:104:105:systemd Resolver,,,:/run/systemd:/usr/sbin/nologintcpdump:x:105:110::/nonexistent:/usr/sbin/nologinsyslog:x:106:111::/home/syslog:/usr/sbin/nologinavahi-autoipd:x:107:115:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/usr/sbin/nologindnsmasq:x:108:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologinstrongswan:x:109:65534::/var/lib/strongswan:/usr/sbin/nologincups-pk-helper:x:110:119:user for cups-pk-helper service,,,:/home/cups-pk-helper:/usr/sbin/nologinlightdm:x:111:120:Light Display Manager:/var/lib/lightdm:/bin/falsesshd:x:112:65534::/run/sshd:/usr/sbin/nologinxrdp:x:113:122::/run/xrdp:/usr/sbin/nologinavahi:x:114:123:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/usr/sbin/nologinpulse:x:115:125:PulseAudio daemon,,,:/var/run/pulse:/usr/sbin/nologinsaned:x:116:127::/var/lib/saned:/usr/sbin/nologinhplip:x:117:7:HPLIP system user,,,:/run/hplip:/bin/falsenvidia-persistenced:x:118:128:NVIDIA Persistence Daemon,,,:/nonexistent:/usr/sbin/nologinuuidd:x:119:130::/run/uuidd:/usr/sbin/nologinyuanyi:x:1000:1000:yuanyi:/home/yuanyi:/bin/bashsystemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
现在出场的这位嘉宾是 cat /etc/passwd | head -n 1
1 root:x:0:0:root:/root:/bin/bash 2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 3 bin:x:2:2:bin:/bin:/usr/sbin/nologin 4 sys:x:3:3:sys:/dev:/usr/sbin/nologin 5 sync:x:4:65534:sync:/bin:/bin/sync 6 games:x:5:60:games:/usr/games:/usr/sbin/nologin 7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin 8 lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin 9 mail:x:8:8:mail:/var/mail:/usr/sbin/nologin 10 news:x:9:9:news:/var/spool/news:/usr/sbin/nologin 11 uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin 12 proxy:x:13:13:proxy:/bin:/usr/sbin/nologin 13 www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin 14 backup:x:34:34:backup:/var/backups:/usr/sbin/nologin 15 list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin 16 irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin 17 gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin 18 nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin 19 _apt:x:100:65534::/nonexistent:/usr/sbin/nologin 20 messagebus:x:101:101::/nonexistent:/usr/sbin/nologin 21 systemd-timesync:x:102:102:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin 22 systemd-network:x:103:104:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin 23 systemd-resolve:x:104:105:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin 24 tcpdump:x:105:110::/nonexistent:/usr/sbin/nologin 25 syslog:x:106:111::/home/syslog:/usr/sbin/nologin 26 avahi-autoipd:x:107:115:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/usr/sbin/nologin 27 dnsmasq:x:108:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin 28 strongswan:x:109:65534::/var/lib/strongswan:/usr/sbin/nologin 29 cups-pk-helper:x:110:119:user for cups-pk-helper service,,,:/home/cups-pk-helper:/usr/sbin/nologin 30 lightdm:x:111:120:Light Display Manager:/var/lib/lightdm:/bin/false 31 sshd:x:112:65534::/run/sshd:/usr/sbin/nologin 32 xrdp:x:113:122::/run/xrdp:/usr/sbin/nologin 33 avahi:x:114:123:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/usr/sbin/nologin 34 pulse:x:115:125:PulseAudio daemon,,,:/var/run/pulse:/usr/sbin/nologin 35 saned:x:116:127::/var/lib/saned:/usr/sbin/nologin 36 hplip:x:117:7:HPLIP system user,,,:/run/hplip:/bin/false 37 nvidia-persistenced:x:118:128:NVIDIA Persistence Daemon,,,:/nonexistent:/usr/sbin/nologin 38 uuidd:x:119:130::/run/uuidd:/usr/sbin/nologin 39 yuanyi:x:1000:1000:yuanyi:/home/yuanyi:/bin/bash 40 systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
如此一来,原先使用空格去分割出每个用户的美梦破碎了,我不得不寻找其它的指令来解决这个问题,接下来我尝试了 awk 'NR==1' /etc/passwd 、 cat /etc/passwd | tail -n 1 | head -n 1 、 tail -n 1 /etc/passwd | head -n 1 、sed -n '1,1p' /etc/passwd ······上述指令在 Linux 下全部输出了我指定的行,而在 Java 程序中执行后,返回的结果却是千奇百怪。awk 指令返回空,没有返回任何数据,cat /etc/passwd | tail -n 1 | head -n 1 不仅把所有的用户信息都放在了同一行,还在每一条信息的前面加上了一个序号,而 tail -n 1 /etc/passwd | head -n 1 则与 cat /etc/passwd 一样,返回了一个无法分割的大杂烩。接下来我来到网络上找寻各种解决方案,尝试了更多的指令,始终无法解决这个问题。由此可推断,这些指令本身都是没有问题的,问题应该是 Java 在传入这些命令到 Linux 系统时破坏了命令本身的某种结构。为了避免在这里浪费过多的时间(博主最近真的忙得焦头烂额,很多事要处理),也为了安抚一下某个苦恼的码畜,我决定改用 I / O 读取 passwd 文件,果然效果立竿见影,通过循环调用 BufferedReader 的 readLine()
方法,把它们打包装进 ArrayList 里面,很轻松地取到了我想要的数据,想怎么炮制它就怎么炮制它。
噩梦 · 无尽的轮回
虽然已经通过 readLine()
实现了对 passwd 的自定义取值,但是我还没解决我的 Java 程序传 Linux 指令后运行出 bug 的问题,我能视而不见,我能善罢甘休吗?我不能!!我必须找出病灶所在,给它动一动外科手术!经过反反复复地查阅相关资料,不断地试错,终于发现 Java 中不能通过 exec()
直接执行管道命令以及部分 Linux 指令,当遇到管道命令及这些出错指令时,我们只需要在指令的前面加上 /bin/sh -c, Java 就能在 Linux 中正确执行传入的指令,我将这部分功能提取出来,定义了一个 executeJava()
方法(详情请参见开发篇)。
没多久又遇到了一个小 bug 出现的现象是我的更新用户所在 shell 的指令一直没有成功执行,检测了很多地方,最后发现问题在我在拼接 Linux 指令的时候漏掉了一个空格。其实每次拼接字符串我都会特别注意地去检查空格的问题,前面涉及的很多指令中也都有拼接空格,为什么在这里就出错了呢,请看下面一条指令,你能否一眼找出缺少空格的位置:
linuxInstructions.executeJava("usermod -g " + shell + username);
正确的指令:
linuxInstructions.executeJava("usermod -s " + shell + " " + username);
我想了想漏掉这个空格的原因,大抵是因为它在两个变量的中间,以致我的注意力都集中在两个变量上了罢。
总结
本次开发中最痛苦莫过于在银河麒麟 V10 与 Windows 10 之间的来回切换,由于在Windows下开发的缘故,我在IDEA上写的代码,都要复制到Linux下重新进行测试,每更改一个命令就要重新复制重新在 Linux 下编译一次,而这个操作集中发生在一开始寻找指令获取 passwd 中的指定一行的那个时期···苦,大概只有自己知道!
不想再记录了,就让 bug 们到此为止吧。
反正当最后成品出来的时候,我的内心是快乐的就足矣。
些许感悟,如果觉得这篇文章对您有帮助的话,请点击文章下方的赞赏,扫描弹出的二维码支持博主创作!!!
本工具已开源至 GitHub:点击访问
评论