python subprocess.call () beklendiği gibi çalışmıyor


11

Bu tavşan deliğini bir kişinin python'da bir kurulum betiği oluşturmaya nasıl gideceğini tanımak için bir araç olarak başladım. Bu görev için python'dan daha iyi alternatifler olacağından eminim, python seçimi basitçe ona aşina olmama dayanıyordu.

Bu komut dosyasının amacı, komut dosyasını çalıştıran makineye ROS yüklemek ve aynı zamanda catkin ortamını kurmaktı. Yol tarifleri sırasıyla burada ve burada bulunabilir .

Şu anda oturur komut dosyası aşağıdaki gibidir:

subprocess.call(["sudo", "sh", "-c", "'echo \"deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main\" > /etc/apt/sources.list.d/ros-latest.list'"])
subprocess.call(["sudo", "apt-key", "adv", "--keyserver", "hkp://ha.pool.sks-keyserver.net:80", "--recv-key", "0xB01FA116"])
subprocess.call(["sudo", "apt-get", "update"])
subprocess.call(["sudo", "apt-get", "install", "ros-kinetic-desktop-full", "-y"])
subprocess.call(["sudo", "rosdep", "init"])
subprocess.call(["rosdep", "update"])
subprocess.call(["echo", '"source /opt/ros/kinetic/setup.bash"', ">>", "~/.bashrc", "source", "~/.bashrc"])
subprocess.call(["sudo", "apt-get", "install", "python-rosinstall", "-y"])
mkdir_p(os.path.expanduser('~') + "/catkin_ws/src")
subprocess.call(["(cd "+ os.path.expanduser('~') + "/catkin_ws/src)"])
subprocess.call(["(cd "+ os.path.expanduser('~') + "/catkin_ws && catkin_make)"])
subprocess.call(["(cd "+ os.path.expanduser('~') + "/catkin_ws && source devel/setup.bash"])

Komut dosyası şu anda çalıştırıldığında hatayla hata veriyor:

Traceback (most recent call last):
  File "setup.py", line 46, in <module>
    subprocess.call(["(cd "+ os.path.expanduser('~') + "/catkin_ws/src)"])
  File "/usr/lib/python2.7/subprocess.py", line 523, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/usr/lib/python2.7/subprocess.py", line 711, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1343, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory

Komutun el ile bir terminal penceresinden yürütüldüğünde doğru çalıştığını doğruladım ve bu nedenle bu komut dosyasının ve kapsamının işletim sistemi içinde nasıl işlendiği hakkında temel bir yanlış anlama olduğuna inanıyorum. Bana çok fazla karışıklık neden olan kısmı, bu dizinin var olduğunu doğrularken neden sağlanan dizini bulamıyor olduğundan şikayet ediyor. Komut python'dan yazdırıldığında ve bir terminal penceresine yapıştırıldığında hatalarla karşılaşılmaz.


Python kendi varos.chdir()
Jacob Vlijm

1
Python 3 kullanıyorsanız,cwdcall
intsco

Yanıtlar:


18

Varsayılan olarak subprocess.call, komutlarımızı çalıştırmak için bir kabuk kullanmaz, bu yüzden gibi komutları kabuklayamazsınız cd.

Komutlarınızı çalıştırmak için bir kabuk kullanmak shell=Trueiçin parametre olarak kullanın . Bu durumda komutlarınızı liste yerine tek bir dize olarak iletmeniz önerilir. Ve yolunuzda da kullanabileceğiniz bir kabuk tarafından çalıştırıldığı ~/için:

subprocess.call("(cd ~/catkin_ws/src && catkin_make)", shell=True)

1
Teşekkür ederim! Subprocess.call bir kabuk kullandığı ve açıkça belirtilmesi gerektiğinin farkında değildim. Yukarıdaki komut tam olarak istendiği gibi çalıştı
beeedy

1
Neden kullanmıyorsunuz os.chdir()?
Jacob Vlijm

3
Nasıl subprocess.call(['catkin_make'], cwd=os.path.expanduser('~/catkin_ws/src'))?
Matt Nordhoff

shell=Truetire olan varsayılan kabuğu çağıracaktır. OP komut dosyası bashisms içeriyorsa bozulabilir. Cevabıma düzenleme ekledim, alternatif çözüm açıkça belirli kabuğu çağırmak olacaktır. Özellikle birisi csh betiği ile uğraşıyorsa yararlıdır
Sergiy Kolodyazhnyy

1
En iyi çözüm Matt Nordhoff önerisidir. Sabit komutlarla shell=True bile kullanıldığında güvenlik açıkları açılır (örn. Savunmasız bir sistemde kabuk vuruşu tetiklenebilir). Temel kural: Kullanmakta önleyebilirsiniz eğer shell=Truesen gerektiğini bunu önlemek. cwdParametre OP istediği çağrının tür yapacağını tam yoktur.
Bakuriu

5

subprocess.call() bir liste bekler, ilk öğe açıkça meşru bir kabuk komutu olur. Örneğin bunu karşılaştırın:

>>> subprocess.call(['echo hello'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/subprocess.py", line 523, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/usr/lib/python2.7/subprocess.py", line 711, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1343, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory
>>> subprocess.call(['echo', 'hello'])
hello
0

Sizin durumunuzda, subprocess.call(["(cd "+ os.path.expanduser('~') + "/catkin_ws/src)"])böyle görünen bir ikili dosya bulmayı bekleyeceksiniz (boşluk karakterlerini belirten ters eğik çizgiyi not edin):

 cd\ /home/user/catkin_ws/src

Bu, sisteminizde bir yerde yaşaması beklenen tek bir ad olarak kabul edilir. Gerçekten yapmak istediğiniz şey:

 subprocess.call(["cd", os.path.expanduser('~') + "/catkin_ws/src"])

Subshell kullanmak için bir neden olmadığından virgül etrafındaki parantezleri kaldırdığımı unutmayın.

DÜZENLE :

Ancak cd, bu durumda kullanımın gereksiz olduğu yorumlarında progo tarafından zaten belirtilmiştir . Florian'ın cevabı ayrıca subprocess.call()kabuk kullanmadığından da bahsediyor . Buna iki şekilde yaklaşabilirsiniz. Bir, kullanabilirsinizsubprocess.call("command string",shell=True)

Diğer bir yol, belirli bir kabuğu açıkça çağırmaktır. Bu, özellikle belirli kabuk gerektiren bir komut dosyası çalıştırmak istiyorsanız kullanışlıdır. Böylece şunları yapabilirsiniz:

subprocess.call(['bash' , os.path.expanduser('~')  + "/catkin_ws/src"  ) ] )

1
call()meşru bir kabuk komutu beklemez; gerçek bir yürütülebilir dosya için bir yol bulmayı bekler. Ve bağımsız bir cdşey çağırmak hiçbir şey başaramaz: CWD, süreç çıktıktan sonra var olmayı bırakan işleme özgü bir değişkendir.
nperson325681

@progo iyi bir nokta, OP'nin komutunu düzenlemeye o kadar odaklandım ki cdburada hiçbir şey yapmayacağını fark etmedim. . . . Ama "meşru" gelince, hala inanıyorum uygun ifadeler - subprocess.call()bulamıyor bir şey verirseniz , gibi ['ls -l'] , meşru olmayacak
Sergiy Kolodyazhnyy

@progo küçük bir düzenleme yaptı, lütfen gözden geçirin
Sergiy Kolodyazhnyy

3

os.chdir()Bunun yerine kullanın .

Varolan cevaplarda bahsedilen konular dışında, dizini değiştirmek için shell=Truene de subprocess.call()burada kullanmayı tercih etmem .

Python kendi dizin değiştirmek için bir yol var os.chdir()(unutmayın import os). ~("ev") çeşitli şekillerde tanımlanabilir, ao os.environ["HOME"].

Bunu tercih etmenin nedenleri buradashell=True okunabilir


0

Kullanımın os.chdir()istenmeyen yan etkilere neden olabileceğini unutmayın , örneğin çoklu iş parçacığı kullanıyorsanız . subprocessyöntemlerin tümü cwd, python işleminizin diğer bölümlerini etkilemeden, istenen alt işlemi bu dizinde çalıştıracak bir anahtar kelime bağımsız değişkeni sağlar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.