我有一个python脚本,我想在启动时在后台运行。这是脚本:
#!/usr/bin/python
from Adafruit_CharLCD import Adafruit_CharLCD
from subprocess import *
from time import sleep, strftime
from datetime import datetime
from datetime import timedelta
from os import system
from os import getloadavg
from glob import glob
#Variables
lcd = Adafruit_CharLCD() #Stores LCD object
cmdIP = "ip addr show eth0 | grep inet | awk '{print $2}' | cut -d/ -f1" #Current IP
cmdHD = "df -h / | awk '{print $5}'" # Available hd space
cmdSD = "df -h /dev/sda1 | awk '{print $5}'" # Available sd space
cmdRam = "free -h"
temp = 0
#Run shell command
def run_cmd(cmd):
p = Popen(cmd, shell=True, stdout=PIPE)
output = p.communicate()[0]
return output
#Initalises temp device
def initialise_temp():
#Initialise
system("sudo modprobe w1-gpio")
system("sudo modprobe w1-therm")
#Find device
devicedir = glob("/sys/bus/w1/devices/28-*")
device = devicedir[0]+"/w1_slave"
return device
#Gets temp
def get_temp(device):
f = open (device, 'r')
sensor = f.readlines()
f.close()
#parse results from the file
crc=sensor[0].split()[-1]
temp=float(sensor[1].split()[-1].strip('t='))
temp_C=(temp/1000.000)
temp_F = ( temp_C * 9.0 / 5.0 ) + 32
#output
return temp_C
#Gets time
def get_time():
return datetime.now().strftime('%b %d %H:%M:%S\n')
#Gets uptime
def get_uptime():
with open('/proc/uptime', 'r') as f:
seconds = float(f.readline().split()[0])
array = str(timedelta(seconds = seconds)).split('.')
string = array[0].split(' ')
totalString = string[0] + ":" + string[2]
return totalString
#Gets average load
def get_load():
array = getloadavg()
average = 0
for i in array:
average += i
average = average / 3
average = average * 100
average = "%.2f" % average
return str(average + "%")
#def get_ram():
def get_ram():
ram = run_cmd(cmdRam)
strippedRam = ram.replace("\n"," ");
splitRam = strippedRam.split(' ')
totalRam = int(splitRam[52].rstrip("M"))
usedRam = int(splitRam[59].rstrip("M"))
percentage = "%.2f" % ((float(usedRam) / float(totalRam)) * 100)
return percentage + "%"
#Gets the SD usage
def get_sd():
sd = run_cmd(cmdSD)
strippedSD = sd.lstrip("Use%\n")
return strippedSD
#Gets the HD usage
def get_hd():
hd = run_cmd(cmdSD)
strippedHD = hd.lstrip("Use%\n")
return strippedHD
def scroll():
while(1):
lcd.scrollDisplayLeft()
sleep(0.5)
#Uptime and IP
def screen1():
uptime = get_uptime()
lcd.message('Uptime %s\n' % (uptime))
ipaddr = run_cmd(cmdIP)
lcd.message('IP %s' % (ipaddr))
#Ram and load
def screen2():
ram = get_ram()
lcd.message('Ram Used %s\n' % (ram))
load = get_load()
lcd.message('Avg Load %s' % (load))
#Temp and time
def screen3():
time = get_time();
lcd.message('%s\n' % (time))
lcd.message('Temp %s' % (temp))
#HD and SD usage
def screen4():
sd = get_sd()
lcd.message('SD Used %s\n' % (sd))
hd = get_hd()
lcd.message('HD Used %s' % (hd))
#Pause and clear
def screenPause(time):
sleep(time)
#In here to reduce lag
global temp
temp = str(get_temp(device));
lcd.clear()
###########################################################################################################
#Initialise
lcd.begin(16,2)
device = initialise_temp()
lcd.clear()
#Testing
#Main loop
while(1):
screen1()
screenPause(5)
screen2()
screenPause(5)
screen3()
screenPause(5)
screen4()
screenPause(5)
我知道我可能已经做过写作方式但是第一次尝试。 我的启动脚本位于/etc/init.d。这是脚本:
#! /bin/sh
### BEGIN INIT INFO
# Provides: LCD looping
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: LCD daemon
# Description: This file should be used to construct scripts to be
# placed in /etc/init.d.
### END INIT INFO
# Author: Foo Bar <foobar@baz.org>
#
# Please remove the "Author" lines above and replace them
# with your own name if you copy and modify this script.
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Loops the LCD screen through LCD.py"
NAME=startup.py
DAEMON=/home/pi/Programming/LCD/startup.py
DAEMON_ARGS=""
PIDFILE=/var/run/daemonLCD.pid
SCRIPTNAME=/etc/init.d/daemonLCD
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/daemonLCD ] && . /etc/default/daemonLCD
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
$DAEMON_ARGS \
|| return 2
# Add code here, if necessary, that waits for the process to be ready
# to handle requests from services started subsequently which depend
# on this one. As a last resort, sleep for some time.
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac
:
我想我已经错过了一些东西,因为当我输入daemonLCD时,它说没有找到命令。 任何输入都会很棒。
由于
答案 0 :(得分:9)
假设您将来可能想要管理多个守护进程,请允许我推荐Supervisord。它比编写和管理自己的init.d脚本简单得多。
例如,启动脚本就像在conf中包含它一样简单:
[program:myscript]
command=/usr/bin/python /path/to/myscript.py
我使用init.d脚本available here。将其重命名为supervisord并将其复制到/etc/init.d/然后运行:
sudo update-rc.d supervisord defaults
我相信init脚本默认以root身份运行supervisord。如果您愿意,可以让它作为另一个用户运行。我不是因为孩子是否以root身份运行,尽管我并不这样认为。继续检查,但是如果他们不在你的supervisord.conf中的python命令之前你可以在你调用脚本的地方粘贴一个sudo。
它不会运行,(或者如果您希望supervisord以非root身份运行但仍希望您的脚本以root身份运行),您可以允许任何人(或一组用户)运行python脚本作为root(尽管你应该确定这个脚本不能由root以外的任何人编辑)。
使用&#34; sudo visudo&#34;编辑您的sudoers文件并将以下内容添加到最后:
USERS ALL=(ALL) NOPASSWD: /path/to/myscript.py
然后确保你的python脚本开头有一个shebang并更改命令以省略python调用,即:
[program:myscript]
command=sudo /path/to/myscript.py
答案 1 :(得分:1)
这是一篇很好的博客文章,内容涉及这个问题:Getting a Python script to run in the background (as a service) on boot
答案 2 :(得分:1)
使用djb中的daemontools
。它比提供的其他答案容易得多。对于初学者,您可以使用apt-get安装守护进程工具,这样您就不必担心从主要内容中获取未知脚本,并且您可以像平常一样通过debian获得更新。如果服务死亡并提供日志记录,daemontools还会负责重新启动服务。这里有daemontools和debian的描述:
djb的页面aout daemontools
:
答案 3 :(得分:0)
这是新Unix / Linux用户犯的经典错误。 /etc/init.d
不在您的路径中,这就是您无法运行daemonLCD的原因。尝试使用完整路径(/etc/init.d/daemonLCD start
)或前置./(./daemonLCD start
)。
脚本需要可执行以上任何一个工作。
答案 4 :(得分:0)
感谢上面的代码。我一直在用它来弄清楚如何在linux机器上设置一个守护进程。
通过一些调整,我可以很好地使用它。
但有些事让我感到困惑。那是通过检查/var/run/myfile.pid的存在来检查进程是否正在运行
那只是pidfile - 不是进程,对吧?
看看/lib/lsb/init-functions.status_of_proc
status_of_proc () {
local pidfile daemon name status OPTIND
pidfile=
OPTIND=1
while getopts p: opt ; do
case "$opt" in
p) pidfile="$OPTARG";;
esac
done
shift $(($OPTIND - 1))
if [ -n "$pidfile" ]; then
pidfile="-p $pidfile"
fi
daemon="$1"
name="$2"
status="0"
pidofproc $pidfile $daemon >/dev/null || status="$?"
if [ "$status" = 0 ]; then
log_success_msg "$name is running"
return 0
elif [ "$status" = 4 ]; then
log_failure_msg "could not access PID file for $name"
return $status
else
log_failure_msg "$name is not running"
return $status
fi
}
仅处理访问PID文件的成功或失败。
现在,我正在构建这个守护进程以使用小型设备。我发现它使用的是BusyBox而且我没有init函数:-( 但我确实有pidof。
所以我添加了
log_success_msg "pidof $NAME is $(pidof -x $NAME)" >> $LOGFILE
log_success_msg "PIDFILE of $NAME is" >> $LOGFILE
sed -n '1p' < $PIDFILE >> $LOGFILE
并检查了$ LOGFILE和lo,看看数字是不同的。
我在两个数字和
上都做了pstree -s -ppidof数字吐出一棵非常短的树,因此它适用于根级进程
但$ PIDFILE号码在分支后呕吐出分支,所以我不认为pstree可以找到该过程。
是的,Joseph Baldwin Roberts的代码中的do_stop会杀死这两个进程。但是如果这个过程以另一种方式被杀死,例如kill -9 12345,$ PIDFILE仍在那里。因此,该守护进程将错误地认为该进程已经开始拒绝启动。