检查 bash 脚本是否是从 shell 或其他脚本/应用程序调用的
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4261876/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Check if bash script was invoked from a shell or another script/application
提问by Sander Marechal
I am writing a bash script to redirect output from another command to the proper location. Basically, when the script is invoked from a shell/commandline I want to send the output to STDOUT. But, when the bash script is executed from some other application (e.g. another bash script, some application, or in my case from the awesome-prompt plugin in my Awesome Window Manager) I want to redirect the output somewhere else.
我正在编写一个 bash 脚本来将另一个命令的输出重定向到正确的位置。基本上,当从 shell/命令行调用脚本时,我想将输出发送到 STDOUT。但是,当 bash 脚本从某个其他应用程序(例如另一个 bash 脚本、某个应用程序,或者在我的例子中从我的 Awesome Window Manager 中的 awesome-prompt 插件执行)时,我想将输出重定向到其他地方。
Is there any way in bash to see how a script was invoked?
在 bash 中有什么方法可以查看脚本是如何被调用的吗?
回答by Paused until further notice.
Try this:
尝试这个:
ps -o stat= -p $PPID
If the result contains "s" (lowercase) it was either run from the command line or backgrounded from within a script. To tell those two apart:
如果结果包含“s”(小写),则它要么是从命令行运行的,要么是在脚本中作为后台运行的。把这两个区分开来:
ps -o stat= -p $$
will contain a "+" if it was not backgrounded.
如果它没有背景,将包含一个“+”。
Here's a table:
这是一个表格:
Run $$ $PPID
CL S+ Ss
CL& S Ss+
Script S+ S+
Script& S S
Script(&) S Ss
Script&(&) S NULL
Where (&) means the child script was backgrounded and & means the parent script (which is what "Script" refers to) that ran it was backgrounded. CL means command line. NULL means that ps output a null and that $PPIDis "1".
其中 (&) 表示子脚本是后台运行的,& 表示运行它的父脚本(即“脚本”所指的内容)是后台运行的。CL 表示命令行。NULL 表示 ps 输出一个空值,即$PPID“1”。
From man ps:
来自man ps:
s is a session leader
+ is in the foreground process group
It should be noted that this answer is based on GNU ps, but the man pages for BSD (including OS X) indicate similar functionality. And GNU psis a hybrid that includes BSD functionality, among others.
应该注意的是,这个答案基于 GNU ps,但 BSD(包括 OS X)的手册页表明了类似的功能。GNUps是一种混合体,其中包括 BSD 功能等。
回答by thkala
I believe that what you really want to know is whether stdout is a terminal or not. If it is then you can (almost) safely assume that it's an interactive session. Try the following snippet:
我相信您真正想知道的是 stdout 是否是终端。如果是,那么您(几乎)可以安全地假设它是一个交互式会话。尝试以下代码段:
if [[ -t 1 ]]; then
echo "Terminal"
else
echo "Not-a-terminal"
fi
The [[ -t 1 ]]command above is what checks if the file descriptor 1 (i.e. stdout) is a terminal or not.
[[ -t 1 ]]上面的命令用于检查文件描述符 1(即 stdout)是否是终端。
EDIT:
编辑:
Please note that this will indicate a non-terminal stdout if you pipe the output to some other program. In that case you might want a more versatile condition that will also check the standard input (file descriptor 0):
请注意,如果您将输出通过管道传输到其他程序,这将指示非终端标准输出。在这种情况下,您可能需要一个更通用的条件来检查标准输入(文件描述符 0):
[[ -t 0 || -t 1 ]]
回答by Rhongomiant
This is a function I adapted from another post about this topic. It matches all the parent processes up to the top against the items listed in the $shellsvariable. When it is done $iscliis set to either 0 or 1. If it is set to 0, then you know it was run from a shell or what you consider shell enough for this purpose. If it is set to 1, then you know a program was involved that is not approved. I use this for scripts I want to run in a shell and via PHP when I want different output to be provided to each.
这是我从另一篇关于该主题的帖子中改编的功能。它将直到顶部的所有父进程与$shells变量中列出的项目相匹配。完成后$iscli设置为 0 或 1。如果设置为 0,则您知道它是从 shell 运行的,或者您认为 shell 足以达到此目的。如果它设置为 1,那么您就知道所涉及的程序未获批准。当我希望为每个脚本提供不同的输出时,我将它用于我想在 shell 中运行的脚本和通过 PHP 运行的脚本。
You will of course need to call the function initially without any parameters before you need $isclito have a value.
当然,在需要$iscli值之前,您首先需要在没有任何参数的情况下调用该函数。
function top_level_parent_pid {
scriptname="${0##*/}"
shells="^bash|^init|^screen|^sh|^ssh|^su|${scriptname}"
pid=${1:-$$}
pidname="`ps --no-heading -o %c -p ${pid}`"
stat=($(</proc/${pid}/stat))
ppid=${stat[3]}
ppidname="`ps --no-heading -o %c -p ${ppid}`"
isclitest="`echo "${ppidname}" | grep -iv -E "${shells}"`"
until [ "${ppid}" -eq "1" ] || [ "${iscli}" = "1" ]; do
if [[ -n "${isclitest}" ]]; then
iscli="1"
else
iscli="0"
top_level_parent_pid ${ppid}
fi
done
}
回答by laher
You could use $PPID
你可以使用 $PPID
Something like
就像是
PARENT=`ps --no-heading -o %c -p $PPID`
echo $PARENT
This would set the PARENT variable to the parent's process name, and then print it to screen.
这会将 PARENT 变量设置为父进程的名称,然后将其打印到屏幕上。
You could then put some if statements based on the value of $PARENT
然后,您可以根据 $PARENT 的值放置一些 if 语句
HTH
HTH

