使用:
Ubuntu 20.04.4 LTS (Focal Fossa)
GNU bash,版本 5.1.16(1)
和
script --version
来自 util-linux 2.34 的脚本
这些命令在终端提示符下运行:
script /home/x/Desktop/clamlog2.cat ; # Log file start.
script --version ; # 2.34 version number, for clarity.
bash /media/x/usb_stick/clamscan.sh ; # virus scan script.
ls ; # example of other commands to Log.
exit ; # Log file end.
cat /home/x/Desktop/clamlog2.cat ; # review Log file in colour.
如何
通过 bash 脚本执行上述终端提示命令?
上述命令的目的是什么?
制作扫描的彩色日志文件。(Clam AntiVirus:扫描仪 0.103.6)
彩色日志不是文本,而是带有颜色的文本,就像您在提示符中看到的那样。
彩色日志文件 = /home/x/Desktop/clamlog2.cat
问题:
bash 脚本在第一行后停止:
script /home/x/Desktop/clamlog2.cat ; # Log file start.
说:
Script started, file is /home/x/Desktop/clamlog2.cat
上述命令在终端提示符下运行。
如何实现自动化?
如何让上述命令在 bash 脚本中运行?
--
答案1
解释
shell 脚本中的行不会模拟键盘输入。每个语句都是一个命令,必须在下一个命令运行之前完成,并且整个脚本在父 shell 的上下文中运行。
在交互式 shell 中script mylog
Enter,你可以输入其他(内) shell,然后您可以输入 eg ,它将在内 shell 中ls
Enter执行。最后,您可以通过输入 退出内 shell 。当看到其他 shell 退出时,它也会退出。当原始 (外) shell 看到退出时,它会继续:它会向您显示提示符并读取您输入的内容。下一个命令 (例如) 将在原始 shell 中执行。ls
exit
Enterscript
script
cat mylog
只要script
运行,外壳就会等待并且不会尝试从终端读取(一般来说:从 stdin 读取;在交互式外壳的情况下,stdin 通常是终端)。script
从终端读取并将输入传递到内壳。
执行脚本中的相同命令序列将使执行脚本的 shell 运行script mylog
并等待其退出,就像在交互式使用的情况下一样。并且就像在交互式使用的情况下一样,内壳将运行由 中继的命令script
,即从其 stdin(通常是终端)读取的任何内容script
。重要的区别是:外壳从常规文件(即不是从 stdin)读取代码,但内壳只能从 stdin 获取代码。内壳无法访问脚本。
您声称脚本在 之后停止script /home/x/Desktop/clamlog2.cat
。但它并没有停止。它等待script
退出;并script
等待内壳退出;内壳等待您输入一些内容。内壳的提示符很可能与您启动的交互式壳的提示符完全一样,因此您可能认为整个脚本已经退出。不,它没有;您在内壳中,在script
外壳中(解释您的脚本文件),而原始的交互式壳甚至更外层。现在,如果您输入,exit
则脚本将继续,您为内壳设置的命令将由解释脚本的壳执行,包括行exit
(cat …
永远不会执行)。
有缺陷的“解决方案”
通过外壳的 stdin 提供脚本,你可以模拟键盘输入。像这样:
# But don't.
bash <./the_script
这bash
将从其 stdin 读取代码,当它调用时script …
,该工具将继承 stdin,因此通过读取其 stdin,它也将从文件中读取。这种方法存在缺陷,因为:
bash
script …
可以并且有时会(在某些情况下必须)在调用之前读取文件script
。实际上script
可能会从您意想不到的位置开始读取文件(即内壳可能会获取代码)。退出后,解释脚本的壳将执行它本来不应该读取的已读取代码。- 即使
bash
读取的内容正是您所希望的,script
也可能会超出预期exit
(在我们的例子中,它将读取该cat …
行)。内壳将获取exit
并按预期退出,但外壳将看不到script
超出预期的内容(cat …
根本不会执行;内壳和外壳都看不到它)。
解决方案:此处文档
正常运行要好得多the_script
。在其中,您可以script
使用重定向的标准输入运行。此示例the_script
使用此处的文档进行重定向:
#!/bin/sh
script mylog <<EOF
ls
date
EOF
cat mylog
现在script
只能从此处文档读取(您不需要exit
,此处文档的唯一结尾就足够了)。请注意,如果ls
您date
有一个从其标准输入读取的命令(例如另一个script
或ffmpeg
),那么就会出现某些工具读取过多的问题,就像上面有缺陷的“解决方案”一样;这将是从此处文档读取过多内容,而不是从整个脚本读取过多内容,但仍然如此。
如果您想要在内部运行的内容script
没有从标准输入读取,或者如果您正确地重定向了想要读取的任何内容的标准输入,那么此处的文档可能是一个很好的解决方案。
解决方案:script --command
另一个解决方案是提供代码(在内壳中运行)作为 的参数script
。来自man 1 script
:
-c, --command command
运行command
而不是交互式 shell。这样,脚本就可以轻松捕获程序的输出,当程序的标准输出不是 tty 时,程序的行为会有所不同。
虽然没有明确说明,但command
被解释为 shell 代码(即不一定是单个可执行文件)。例如:
#!/bin/sh
script mylog -c '
ls
date
'
cat mylog
注意,内层 shell 解释器ls; date
不是交互式 shell。它不会打印提示,而且您的别名可能不起作用。
最后说明
还有其他工具可以为您提供 shell 或类似 shell 的界面,或者只是出于某种原因从 stdin 读取。想象一下,script …
您有bash
、ssh user@server
甚至。如果您从 shell 脚本调用其中任何一个,请不要指望脚本的下一行(几行)到达该工具。该机制与解释的完全一样,它并不特定于。我们使用此处文档的解决方案是通用的。我们使用的解决方案显然特定于,但其他工具可能支持类似的方式来提供代码/输入作为命令行参数(例如,)。python3
cat
script
script -c
script
bash -c code
ssh user@server code
答案2
补充 Kamil 的回答......
#!/bin/sh
script /home/x/Desktop/clamlog2.cat -c '
clear # reduce scroll-back text / screens.
bash /media/x/usb_stick/clamscan.sh # virus scan script.
echo "Ctrl-Shift-UParrow # keyboard shortcut scroll-back reminder."
'
cat /home/x/Desktop/clamlog2.cat
Kamil对原始(外)壳与内壳的回答......
让我想起了《星际迷航:下一代》中的莫里亚蒂教授
小学,亲爱的数据
莫里亚蒂教授召唤全息甲板拱门
https://www.youtube.com/watch?v=msjQKkkW2Wo
皮卡德舰长……
计算机结束程序。
……
计算机结束程序。
计算机……