Python 推送通过操作系统
我正在使用crontab为我的minecraft服务器运行维护脚本。大多数情况下,它工作正常,除非crontab尝试使用重启脚本。如果手动运行重启脚本,则不会出现任何问题。因为我相信这与路径名有关,所以我试图确保它总是从minecraft目录执行任何minecraft命令。所以我将命令封装在pushd/popd中:Python 推送通过操作系统,python,cron,centos,Python,Cron,Centos,我正在使用crontab为我的minecraft服务器运行维护脚本。大多数情况下,它工作正常,除非crontab尝试使用重启脚本。如果手动运行重启脚本,则不会出现任何问题。因为我相信这与路径名有关,所以我试图确保它总是从minecraft目录执行任何minecraft命令。所以我将命令封装在pushd/popd中: os.system("pushd /directory/path/here") os.system("command to sent to minecraft") os.system
os.system("pushd /directory/path/here")
os.system("command to sent to minecraft")
os.system("popd")
下面是一个交互式会话,将minecraft排除在等式之外。一个简单的“ls”测试。正如您所看到的,它根本不从pushd目录运行os.system命令,而是从/etc/运行,我在其中运行python来说明我的观点。显然,pushd不是通过python工作的,所以我想知道我还能如何实现这一点。谢谢
>>> def test():
... import os
... os.system("pushd /home/[path_goes_here]/minecraft")
... os.system("ls")
... os.system("popd")
...
>>> test()
~/minecraft /etc
DIR_COLORS cron.weekly gcrypt inputrc localtime mime.types ntp ppp rc3.d sasldb2 smrsh vsftpd.ftpusers
DIR_COLORS.xterm crontab gpm-root.conf iproute2 login.defs mke2fs.conf ntp.conf printcap rc4.d screenrc snmp vsftpd.tpsave
X11 csh.cshrc group issue logrotate.conf modprobe.d odbc.ini profile rc5.d scsi_id.config squirrelmail vz
adjtime csh.login group- issue.net logrotate.d motd odbcinst.ini profile.d rc6.d securetty ssh warnquota.conf
aliases cyrus.conf host.conf java lvm mtab openldap protocols redhat-release security stunnel webalizer.conf
alsa dbus-1 hosts jvm lynx-site.cfg multipath.conf opt quotagrpadmins resolv.conf selinux sudoers wgetrc
alternatives default hosts.allow jvm-commmon lynx.cfg my.cnf pam.d quotatab rndc.key sensors.conf sysconfig xinetd.conf
bashrc depmod.d hosts.deny jwhois.conf mail named.caching-nameserver.conf passwd rc rpc services sysctl.conf xinetd.d
blkid dev.d httpd krb5.conf mail.rc named.conf passwd- rc.d rpm sestatus.conf termcap yum
cron.d environment imapd.conf ld.so.cache mailcap named.rfc1912.zones pear.conf rc.local rsyslog.conf setuptool.d udev yum.conf
cron.daily exports imapd.conf.tpsave ld.so.conf mailman netplug php.d rc.sysinit rwtab shadow updatedb.conf yum.repos.d
cron.deny filesystems init.d ld.so.conf.d makedev.d netplug.d php.ini rc0.d rwtab.d shadow- vimrc
cron.hourly fonts initlog.conf libaudit.conf man.config nscd.conf pki rc1.d samba shells virc
cron.monthly fstab inittab libuser.conf maven nsswitch.conf postfix rc2.d sasl2 skel vsftpd
sh: line 0: popd: directory stack empty
===
(使用python 2.4的CentOS server)每个shell命令在单独的进程中运行。它生成一个shell,执行pushd命令,然后shell退出 只需在相同的shell脚本中编写命令:
os.system("cd /directory/path/here; run the commands")
更好的(也许)方法是使用模块:
我认为您不能在
os.system()中调用pushd
>>> import os
>>> ret = os.system("pushd /tmp")
sh: pushd: not found
也许只是可能您的系统实际上提供了一个触发shell内部函数的pushd
二进制文件(我想我以前在FreeBSD上见过这个),但是进程的当前工作目录不能受其他进程的影响——因此您的第一个system()
启动一个shell,运行一个假设的pushd
,启动shell,运行ls
,启动shell,运行假设的popd
。。。这些都不会相互影响
您可以使用os.chdir(“/home/path/”)
来更改路径:无需使用pushd
——只需使用os.chdir
:
>>> import os
>>> os.getcwd()
'/Users/me'
>>> os.chdir('..')
>>> os.getcwd()
'/Users'
>>> os.chdir('me')
>>> os.getcwd()
'/Users/me'
pushd
和popd
有一些附加功能:它们将以前的工作目录存储在一个堆栈中-换句话说,您可以pushd
五次,做一些事情,然后popd
五次,最终到达开始的位置。您在这里没有使用它,但它可能对其他搜索类似问题的人有用。以下是您可以模拟它的方式:
# initialise a directory stack
pushstack = list()
def pushdir(dirname):
global pushstack
pushstack.append(os.getcwd())
os.chdir(dirname)
def popdir():
global pushstack
os.chdir(pushstack.pop())
在Python 2.5及更高版本中,我认为更好的方法是使用上下文管理器,如下所示:
import contextlib
import os
@contextlib.contextmanager
def pushd(new_dir):
previous_dir = os.getcwd()
os.chdir(new_dir)
try:
yield
finally:
os.chdir(previous_dir)
然后,您可以按如下方式使用它:
with pushd('somewhere'):
print os.getcwd() # "somewhere"
print os.getcwd() # "wherever you started"
通过使用上下文管理器,您将是异常和返回值安全的:即使您从上下文块内部抛出异常或返回,您的代码也将始终返回到它的起始位置
您还可以在嵌套块中嵌套pushd调用,而不必依赖全局目录堆栈:
with pushd('somewhere'):
# do something
with pushd('another/place'):
# do something else
# do something back in "somewhere"
或者创建一个与“with”一起使用的类
import os
class pushd: # pylint: disable=invalid-name
__slots__ = ('_pushstack',)
def __init__(self, dirname):
self._pushstack = list()
self.pushd(dirname)
def __enter__(self):
return self
def __exit__(self, exec_type, exec_val, exc_tb) -> bool:
# skip all the intermediate directories, just go back to the original one.
if self._pushstack:
os.chdir(self._pushstack.pop(0)))
if exec_type:
return False
return True
def popd(self) -> None:
if len(self._pushstack):
os.chdir(self._pushstack.pop())
def pushd(self, dirname) -> None:
self._pushstack.append(os.getcwd())
os.chdir(dirname)
with pushd(dirname) as d:
... do stuff in that dirname
d.pushd("../..")
d.popd()
如果你真的需要一个堆栈,即如果你想做几个pushd和popd,
见上文第101段
如果没有,只需:
olddir = os.getcwd()
os.chdir('/directory/path/here')
os.system("command to sent to minecraft")
os.chdir(olddir)
我对“~/minecraft/etc”这句话有点困惑。对我来说,它看起来像是一个简单的例子,说明了os.system
生成了一个子shell。。。执行bash-c“pushd目录”
,bash-c“popd”
将得到相同的结果。。。为什么不直接使用os.chdir
?nvm关于混淆线,它是正在执行的pushd
的输出,但是分析仍然有效,您的命令不起作用,因为os.system
生成了一个子shell。。。。一旦子shell完成,pushd/popd上下文就会变得毫无意义;我最近才开始使用subprocess(这里是新的程序员,很明显),我想更好地了解它。它可以工作,但是我必须按住CTRL+C键才能返回python提示符。奇怪。值得注意的是,在以UNC路径为参数的Windows计算机上使用pushd
,会导致Windows自动将网络驱动器映射到该路径。使用cd
不适用于UNC路径,也不适用于Popen
。如果需要该功能,请使用Popen(r'pushd\\server\folder&dir&popd',shell=True)
。还要注意,
不会在Windows中分隔命令,但是&
会。我已经看到映射Windows驱动器可能需要30秒。你真的想等你的python脚本运行那么久吗?是的。这正是我想要的。非常感谢。仅当上一个目录是另一个目录的直接父目录时,此选项才有效。@DaveKennedy,True。我想你也可以说,只有当目录是'/directory/path/here'
时,被接受的答案才有效,不是吗?我喜欢这个想法,它更优雅,更具pythonic:)这就是我一直在寻找的。但是,如果with语句中出现异常,则不会弹出此代码,因为@contextmanager不处理异常,您需要用try来包围产量。。。finally@MaximeViargues还有contextlibclosing
方法,它可以满足try…finally的要求,只是名称选择不当,依我拙见因为popd是隐式的,所以您没有像sh脚本中那样的push/pop对称
olddir = os.getcwd()
os.chdir('/directory/path/here')
os.system("command to sent to minecraft")
os.chdir(olddir)