从终端提示符运行。如何让 bash 脚本运行?

从终端提示符运行。如何让 bash 脚本运行?

使用:
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 mylogEnter,你可以输入其他(内) shell,然后您可以输入 eg ,它将在内 shell 中lsEnter执行。最后,您可以通过输入 退出内 shell 。当看到其他 shell 退出时,它也会退出。当原始 (外) shell 看到退出时,它会继续:它会向您显示提示符并读取您输入的内容。下一个命令 (例如) 将在原始 shell 中执行。lsexitEnterscriptscriptcat 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,它也将从文件中读取。这种方法存在缺陷,因为:

  • bashscript …可以并且有时会(在某些情况下必须)在调用之前读取文件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,此处文档的唯一结尾就足够了)。请注意,如果lsdate有一个从其标准输入读取的命令(例如另一个scriptffmpeg),那么就会出现某些工具读取过多的问题,就像上面有缺陷的“解决方案”一样;这将是从此处文档读取过多内容,而不是从整个脚本读取过多内容,但仍然如此。

如果您想要在内部运行的内容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 …您有bashssh user@server甚至。如果您从 shell 脚本调用其中任何一个,请不要指望脚本的下一行(几行)到达该工具。该机制与解释的完全一样,它并不特定于。我们使用此处文档的解决方案是通用的。我们使用的解决方案显然特定于,但其他工具可能支持类似的方式来提供代码/输入作为命令行参数(例如,)。python3catscriptscript -cscriptbash -c codessh 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

皮卡德舰长……
计算机结束程序。
……
计算机结束程序。
计算机……

相关内容