正在运行的脚本是否可以将自身移至后台?
我有一个目标:我运行脚本:./script.sh
。该脚本要求我输入密码:
echo -n PASSWORD:
read -s pass
if [ "${scriptPassword}" == "$pass" ] && [[ ${pass_counter} = 0 ]]; then
pass_counter = $ ((pass_counter + 1))
echo "PASSWORD OK"
然后我想达到与按Ctrl+Z
然后运行命令相同的效果bg
。我可以在脚本中运行此类命令吗?
我希望脚本开始工作,就好像它是从 启动的一样
nohup ./script.sh &
,但只有在用户输入正确的密码之后。
答案1
1. 直接方法
这有点类似于豪克·拉金的回答但更简单。当您的脚本完成其交互业务后,执行以下操作
(kill -STOP $$; kill -CONT $$) &
sleep 1
在这里,脚本生成一个非常小的(异步)子 shell 来停止它(脚本进程),与+Ctrl非常相似Z,然后使用续直觉信号,与实际信号非常相似bg
。您甚至可能不需要sleep
;我只是认为如果脚本在信号进来时不做任何重要的事情可能会更安全。
我已经对此进行了测试,但只是表面上的,所以如果您在真实的应用程序上下文中使用它,可能会感到惊讶。
____________
*不同之处在于Ctrl+Z发送 SIGTSTP。您可以在脚本中使用 SIGTSTP 而不是 SIGSTOP。我用 SIGSTOP 对其进行了测试,如果有效,我认为没有任何理由更改它。
2. 可以说更简单(也许更便携?)
让脚本异步调用自身。
if [ "$exported_pass" != "$scriptPassword" ] 然后 [ 在此插入适当的代码以供阅读经过来自用户和循环] [直到它是正确的(或者尝试了太多,所以我们退出)。 ] # 所以此时,"$scriptPassword" == "$pass" 导出的通行证=“$通行证” 导出exported_pass nohup "$0" "$@" & 出口 菲
脚本第一次运行时$exported_pass
不会被设置,因此它会进入if
-then
并询问密码。然后它将其放入exported_pass
环境变量中并异步调用自身 - 然后主(父)进程退出。该脚本的第二次调用在后台运行,会在环境中看到密码,然后继续执行其工作。
答案2
您可以在运行脚本之前在父shell中设置一个trap,以便脚本可以触发bg
.问题是脚本运行时陷阱没有执行。
由于终端只是发送SIGSTOP
到脚本(之后父 shell 再次获得控制权),所以技巧是让脚本自己执行此操作:
# preparation in the parent shell
trap 'bg %%' USR1
剧本:
#! /bin/bash
# parent shell has executed: trap 'bg %%' USR1
# pass or determine this value
PARENT_SHELL_PID=5646
read -p "enter value: " input
kill -USR1 $PARENT_SHELL_PID # execution of this in parent shell is delayed
kill -STOP $$ # returns control to parent shell
sleep 1000
寻找包装脚本
如果可以接受两个脚本并获取其中一个脚本(即在当前 shell 上下文中运行它而不是作为子 shell),那么它会变得更加容易:
包装脚本:
PARENT_SHELL_PID=$$ ./script.sh
bg %%
实际脚本:
#! /bin/bash
test -z "$PARENT_SHELL_PID" && exit 2
read -p "enter value: " input
# return control to sourced wrapper script
kill -STOP $$
# continue in the background
sleep 1000
两者都运行
. wrapper.sh
答案3
是否有可能移动后台 shell 的运行脚本?
“移动”的使用令人困惑。你指的是其他动词,很可能(我猜不出是哪个)。我从字面上理解......
A外壳脚本只是一个文件(与过程解释该脚本,你可以有一些进程 - 或没有 - 运行该脚本)。你可以移动它(用mv(1)
或使用重命名(2)在某些程序中)在它运行时。但解释它的 shell 已经打开了一些文件描述符就这样,这不会改变任何事情。实际上,你不想移动脚本(并且您不移动进程或作业;但是您可以移动文件)。 “移动”动词非常令人困惑(至少对我来说,我不是以英语为母语的人),我不明白你真正想做的是什么以及为什么。
(另一个问题是当你覆盖执行期间的脚本,但你不会问这个)
看起来您想要一些程序模仿(伪)终端内用户的操作。阅读tty 揭秘页面(终端和伪终端非常复杂,我忘记了细节)。使用预计模仿终端内的用户。
顺便说一句,在脚本中管理密码是有风险的(安全漏洞很容易制作)并且容易出错,所以气味非常难闻。我会尽力避免这种情况,例如通过使用ssh
公钥和私钥。
因此,最好重新设计整个系统,以避免自动提供密码(在脚本内)。
您显然想要这样做(但我不清楚您是否想在终端中自己执行此操作,或者从另一个脚本内部执行此操作):
CTRL+Z
bg %%
这是关于作业控制。事实上,后台运行的是一个运行解释脚本的 shell 或其他普通可执行程序的进程,这一事实是无关紧要的。Unix shell从内核的角度来看是普通程序。 IIRC,工作控制与进程组。
在评论中,您提到连接到某个数据库。最多关系型数据库管理系统客户端程序提供了某种方式以更合适的方式给出密码(也许--login-path
用于mysql
命令)。如果你想从另一个脚本中做到这一点这里的文档可能会很方便(这里的文档可以包含或合成一些 SQL 命令)。另请注意,当身份验证失败时,RDBMS 系统不会更改其数据库。
我可以在脚本中运行此类命令吗?
bg %%
我不明白您想在脚本中运行什么命令(是)。如果您想从脚本驱动作业控制(但我相信您不应该),那么expect
可能更合适。
我希望脚本开始工作,
nohup ./scripts.sh &
但只有在输入正确的密码之后
那个编辑让我困惑更。您所说的密码是什么(我不确定您的脚本是否为某些 RDBMS 服务器提供了密码,或者需要一个密码才能完全运行)?我猜您有一些长时间运行的脚本正在执行与数据库相关的操作(例如持续几个小时的备份)。如果确实如此,您需要提出不同的问题。例如,您可以将(交互式输入)密码存储在某处,然后批量运行备份(也许使用batch
命令一些这里的文档)。顺便说一句,各种 RDBMS 有不同的方式来提供密码和进行身份验证,因此您确实需要在未来的问题中提及您正在使用的实际 RDBMS。
因此,请考虑改进您的问题,以激发其更多动机并提供更多背景信息。我只是猜测,而且我可能猜测得很错!
或者也许你想要相当于守护进程(3)在你的壳里?这又会提出另一个问题(因为 bash 是自由软件,您可以随时修补它以添加新的内置在里面)。我认为(但我一点也不确定)exec
shell 内置可能有用。