Saya memulai lubang kelinci ini sebagai sarana untuk membiasakan diri dengan bagaimana orang akan membuat skrip pengaturan dengan python. Pilihan python hanya berakar pada keakraban saya dengan itu sementara saya yakin akan ada alternatif yang lebih baik daripada python untuk tugas ini.
Tujuan skrip ini adalah menginstal ROS ke mesin yang menjalankan skrip dan juga mengatur lingkungan catkin. Arah dapat ditemukan di sini dan di sini , masing-masing.
Script saat ini duduk adalah sebagai berikut:
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"])
Ketika skrip saat ini berjalan itu kesalahan keluar dengan kesalahan:
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
Saya telah memverifikasi bahwa perintah itu berfungsi dengan benar ketika dieksekusi secara manual dari jendela terminal, dan karena itu saya percaya ini adalah kesalahpahaman mendasar tentang bagaimana skrip ini dan ruang lingkupnya ditangani dalam OS. Bagian yang menyebabkan saya banyak kebingungan adalah mengapa ia mengeluh bahwa ia tidak dapat menemukan direktori yang disediakan, sementara saya telah memverifikasi bahwa direktori ini ada. Ketika perintah agak dicetak dari python dan disisipkan ke jendela terminal tidak ada kesalahan yang ditemui.
sumber
os.chdir()
cwd
call
Jawaban:
Secara default
subprocess.call
tidak menggunakan shell untuk menjalankan perintah kami sehingga Anda tidak dapat shell perintah seperticd
.Untuk menggunakan shell untuk menjalankan perintah Anda gunakan
shell=True
sebagai parameter. Dalam hal ini disarankan untuk meneruskan perintah Anda sebagai string tunggal daripada sebagai daftar. Dan karena dijalankan oleh shell yang dapat Anda gunakan~/
di jalur Anda juga:sumber
os.chdir()
?subprocess.call(['catkin_make'], cwd=os.path.expanduser('~/catkin_ws/src'))
?shell=True
akan memanggil shell default, yang merupakan tanda hubung. Jika skrip yang berisi bashisme OP itu mungkin rusak. Saya telah menambahkan edit pada jawaban saya, solusi alternatif adalah dengan secara eksplisit memanggil shell tertentu. Terutama berguna jika seseorang berurusan dengan skrip cshshell=True
bahkan dengan perintah tetap membuka kerentanan keamanan (mis. Shellshock dapat dipicu pada sistem yang rentan). Aturan praktis: jika Anda dapat menghindari penggunaanshell=True
Anda harus menghindarinya. Thecwd
parameter sana persis melakukan jenis panggilan OP ingin.subprocess.call()
mengharapkan daftar, dengan item pertama jelas merupakan perintah shell yang sah. Bandingkan ini misalnya:Dalam kasus Anda, Anda
subprocess.call(["(cd "+ os.path.expanduser('~') + "/catkin_ws/src)"])
akan menemukan biner yang mirip (perhatikan backslash yang menunjuk ruang karakter):Itu diperlakukan sebagai satu nama tunggal yang diharapkan untuk hidup di suatu tempat di sistem Anda. Apa yang benar-benar ingin Anda lakukan adalah:
Perhatikan bahwa saya telah menghapus tanda kurung di sekitar koma, karena tidak ada alasan untuk menggunakan subkulit.
EDIT :
Tetapi telah disebutkan oleh progo dalam komentar bahwa menggunakan
cd
dalam kasus ini berlebihan. Jawaban Florian juga menyebutkan dengan benar bahwasubprocess.call()
tidak menggunakan shell. Anda bisa mendekati itu dengan dua cara. Satu, Anda bisa menggunakannyasubprocess.call("command string",shell=True)
Cara lain, adalah dengan memanggil shell spesifik secara eksplisit. Ini sangat berguna jika Anda ingin menjalankan skrip yang memerlukan shell tertentu. Dengan demikian Anda dapat melakukan:
sumber
call()
tidak mengharapkan perintah shell yang sah; ia mengharapkan untuk menemukan jalur ke executable yang sebenarnya. Dan memanggil mandiricd
tidak mencapai apa-apa: CWD adalah variabel proses spesifik yang tidak ada lagi setelah proses keluar.cd
tidak akan melakukan apa pun di sini. . . . Tetapi untuk "sah", itu masih merupakan ungkapan yang tepat saya percaya - jika saya memberikansubprocess.call()
sesuatu yang tidak dapat ditemukan, seperti['ls -l']
, itu tidak akan sahGunakan
os.chdir()
sebagai gantinya.Terlepas dari masalah, yang disebutkan dalam jawaban yang ada, saya tidak akan suka menggunakan
shell=True
, atau disubprocess.call()
sini untuk mengubah direktori.Python memiliki caranya sendiri dalam mengubah direktori
os.chdir()
(jangan lupaimport os
).~
("rumah") dapat didefinisikan dalam beberapa cara, aoos.environ["HOME"]
.Alasan untuk memilih itu
shell=True
bisa dibaca di sinisumber
Perhatikan bahwa menggunakan
os.chdir()
dapat menyebabkan efek samping yang tidak diinginkan, misalnya jika Anda menggunakan multithreading .subprocess
metode semua memberikancwd
argumen kata kunci yang akan menjalankan subproses yang diminta dalam direktori itu, tanpa mempengaruhi bagian lain dari proses python Anda.sumber