web-dev-qa-db-ja.com

os.systemを介してプッシュ

Crontabを使用して、Minecraftサーバーのメンテナンススクリプトを実行しています。 crontabが再起動スクリプトを使用しようとしない限り、ほとんどの場合は正常に機能します。再起動スクリプトを手動で実行しても、問題はありません。パス名と関係があると思うので、常にminecraftディレクトリからminecraftコマンドを実行していることを確認しようとしています。だから私はpushd/popdにコマンドを入れています:

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

以下は、Minecraftを方程式から外すインタラクティブセッションです。単純な「ls」テスト。ご覧のとおり、プッシュされたディレクトリからos.systemコマンドを実行するのではなく、実行していたディレクトリである/ etc /から実行しますpython 。明らかにpushedは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)

19

各シェルコマンドは、個別のプロセスで実行されます。シェルを生成し、pushdコマンドを実行してから、シェルを終了します。

同じシェルスクリプトでコマンドを書くだけです。

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

より良い(おそらく)方法は subprocess モジュールを使用することです:

from subprocess import Popen
Popen("run the commands", Shell=True, cwd="/directory/path/here")
12
Josh Lee

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"

コンテキストマネージャーを使用すると、例外と戻り値が安全になります。例外をスローしたり、コンテキストブロック内から戻ったりしても、コードは常に元の場所にcdで戻ります。

グローバルディレクトリスタックに依存せずに、ネストされたブロックにプッシュされた呼び出しをネストすることもできます。

with pushd('somewhere'):
    # do something
    with pushd('another/place'):
        # do something else
    # do something back in "somewhere"
75
spiralman

pushdpopdには、いくつかの追加機能があります。以前の作業ディレクトリをスタックに格納します。つまり、pushdを5回実行し、いくつかの処理を実行して、popd 5回、開始した場所に到達します。ここでは使用していませんが、このような質問を検索している他の人にとっては役立つかもしれません。これはあなたがそれをエミュレートする方法です:

# 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())
4
naught101

os.system()呼び出し内からpushdを呼び出すことはできないと思います。

_>>> 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
sarnold

pushdを使用する必要はありません-os.chdirを使用するだけです:

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

または、「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()
0
Gary