1

Hello I am trying to source of file say check.setup from my pythons script. Code

import os
os.system("source /fullpathhere/check.setup")

It says command not found. Surprisingly I can source the same file directly from the shell. check.setup is csh file. It is sourcing other .csh files and setting few environment variable I saw few answers here but no one could possibly solve the problem. PS: I tried to write bash file instead of python. I also tried using subprocess.Popen. Problem persists. Aashish

  • 1
    I'm unsure of the likelyhood of this being correct (thus comment not answer), but I've heard that sometimes `source` is actually an alias for `.`. It might be worthwhile to see if `. /fullpathhere/check.setup` works as your command. – Delioth Jun 22 '17 at 21:15
  • What is your default shell on your machine ? See that with `echo $SHELL` and test first this command on your `source /fullpath/check.setup` directly in your console to see the result. – glegoux Jun 22 '17 at 21:20
  • 6
    Both source and . are built-in shell commands and not something you can execute like this. But even if you could, there would be no point, because os.system spawns a subshell: any env vars set in that subshell would immediately be lost when it exits as the command returns. – Daniel Roseman Jun 22 '17 at 21:31
  • @ Delioth I tried {. /fullpathhere/check.setup). It does not work. Same error – Aashish sharma Sharma Jun 22 '17 at 21:36
  • @gkegoux its tcsh. Apologies but I dont understand your suggestion. you want me to write script using Tcsh? I tried bash it gives same result. – Aashish sharma Sharma Jun 22 '17 at 21:37
  • @DanielRoseman Actually I am doing some work on the shell which involves series of steps like sourcing some files then calling some other python script. So all I want is to write one script that I can execute rather than doing say 20 steps manually. So few steps involves sourcing some files as I have mentioned – Aashish sharma Sharma Jun 22 '17 at 21:39
  • There is **absolutely no benefit** to sourcing a shell script from a Python interpreter. To the extent that it's possible at all (by spawning a shell interpreter and telling that interpreter to source the script), it has all the negative effects that simply executing that script as a subprocess would have (such as the changes made by the script not persisting past the end of its execution). – Charles Duffy Jun 23 '17 at 19:55

2 Answers2

0

use popen

subprocess.Popen('source ./fullpathhere/check.setup', shell=True)
tkyass
  • 2,968
  • 8
  • 38
  • 57
  • Hey I used Popen. (Sort of). from subprocess import call. then call('source ./fullpath/check.setup', shell= True). It didnt work. Same problem – Aashish sharma Sharma Jun 22 '17 at 21:48
  • `source` is a bashism; to work in POSIX sh, it needs to be `.` – Charles Duffy Jun 23 '17 at 19:54
  • though at that point there is **absolutely no benefit** of using either `source` or `.` over just `subprocess.Popen(['sh', './fullpathhere/check.setup'])` (substituting an alternate interpreter if one prefers) without any `shell` argument at all. – Charles Duffy Jun 23 '17 at 19:58
0

Why didn't tag your posting as csh, even though you explicitly mention csh in your question....

There is no executable namend source (you can verify it by typing bin/which source. Well, you pointed out by yourself, that this is supposed to be done by csh, but how should Python know that it needs to invoke csh, if you don't tell it?

I don't have a csh on my system, but if I remember right from the time a couple of decades ago, where I indeed used csh for programming, you can do something like

os.system("csh -c fullpathhere/check.setup")

Actually, I would also specify the -f flag for skipping .cshrc, unless you really need that to be sourced as well.

user1934428
  • 19,864
  • 7
  • 42
  • 87
  • Given how `system()` is implemented, you're telling the OP to run `sh -c "csh -c fullpathhere/check.setup"`. That's... really quite silly. – Charles Duffy Jun 23 '17 at 19:59
  • Thanks for the suggestion for tag. I have added now. I couldnt exactly find cshell. I tried doing that but problem is I dont have permission to access the file. I am not even authorized to give permission using chmod. So i made another csh file from python script sourced my check.setup from that. I could give permission to file I made from python script as I created it. I then executed my csh file from python – Aashish sharma Sharma Jun 23 '17 at 20:03
  • @Charles Duffy: Isn't Python clever enough to omit the `sh` process in this case (as Perl would do in this case)? But even if an additional POSIX shell process is created to run the C-Shell, I don't consider it that bad (given the convenience of using `os.system`) . – user1934428 Jul 03 '17 at 10:30
  • The biggest costs are to correctness, not convenience. Invoking a shell means your data needs to be escaped to be correctly parsed; invoking two shells means it needs to be escaped twice. And invoking a shell at all means you're vulnerable to initialization-time issues such as shellshock. And no, Python (thankfully!) doesn't try to be clever and do things behind the programmer's back. – Charles Duffy Jul 03 '17 at 11:51
  • Actuall, the escaping itself is maybe not the problem: You only escape ones (for the immediately calling shell, i.e. `sh`), unless your "lower" shell has it's own set of very different escaping mechanism, in which case indeed things get hairy. As for correctness, I see the bigger risk in that (AFIK) it is not precisely specified which shell the "implicitly called" one is. OTOH, people using `os.system` do it exactly because they want the shell to fiddle with their command line (example: wildcard expansion), and my solution is close to the OP's code. I understand your point, though. – user1934428 Jul 03 '17 at 16:24
  • 1
    @user1934428, you can't only escape once without risking shell injection attacks if you're handling untrusted data. Let's say you're trying to pass a file named `/uploads/$(rm -rf ~)'$(rm -rf ~)'`, or `/uploads/' '/etc/passwd` (the latter as created by `mkdir $'\' \''`, the former as created by `touch $'$(rm -rf ~)\'$(rm -rf ~)\'`) -- if you ran `system("sh -c '/run/my/script " + filename + "'")` you'd have a bad day with either, despite having a single layer of explicit quoting via the literal single-quotes in the text (since the literal single quotes in the filenames end them). – Charles Duffy Jul 04 '17 at 12:45