Подтвердить что ты не робот

Pushd через os.system

Я использую crontab для запуска обслуживания script для моего сервера minecraft. В большинстве случаев он отлично работает, если crontab не пытается использовать перезапуск script. Если я запускаю перезапуск script вручную, проблем нет. Поскольку я считаю, что это связано с именами путей, я стараюсь, чтобы он всегда выполнял команду minecraft из каталога minecraft. Поэтому я заключу команду в pushd/popd:

os.system("pushd /directory/path/here")
os.system("command to sent to minecraft")
os.system("popd")

Ниже приведена интерактивная сессия, в результате которой minecraft выходит из уравнения. Простой тест "ls". Как вы можете видеть, он вообще не запускает команду os.system из каталога pushd, но вместо этого из /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

=== (CentOS-сервер с python 2.4)

4b9b3361

Ответ 1

Каждая команда оболочки запускается в отдельном процессе. Он порождает оболочку, выполняет команду pushd, а затем выходит из оболочки.

Просто напишите команды в той же оболочке script:

os.system("cd /directory/path/here; run the commands")

Более приятным (возможно) способом является модуль subprocess:

from subprocess import Popen
Popen("run the commands", shell=True, cwd="/directory/path/here")

Ответ 2

В Python 2.5 и более поздних версиях я думаю, что лучший метод будет использовать диспетчер контекста, например:

import contextlib
import os


@contextlib.contextmanager
def pushd(new_dir):
    previous_dir = os.getcwd()
    os.chdir(new_dir)
    yield
    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"

Ответ 3

Я не думаю, что вы можете вызвать pushd из вызова os.system():

>>> import os
>>> ret = os.system("pushd /tmp")
sh: pushd: not found

Возможно, может быть, ваша система фактически предоставляет двоичный код pushd, который запускает внутреннюю функцию оболочки (Я думаю, что видел это на FreeBSD раньше У FreeBSD есть такие трюки, как это, но не для pushd), но на текущий рабочий каталог процесса не могут влиять другие процессы - поэтому ваш первый system() запускает оболочку, запускает гипотетический pushd, запускает оболочку, запускает ls, запускает оболочку, запускает гипотетический popd... ни один из которых не влияет друг на друга.

Вы можете использовать os.chdir("/home/path/") для изменения пути: http://docs.python.org/library/os.html#os-file-dir

Ответ 4

Не нужно использовать pushd - просто используйте os.chdir:

>>> import os
>>> os.getcwd()
'/Users/me'
>>> os.chdir('..')
>>> os.getcwd()
'/Users'
>>> os.chdir('me')
>>> os.getcwd()
'/Users/me'

Ответ 5

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())

Ответ 6

Или создайте класс для использования с 'с'

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()