0

When i run from bash:

# su -c "psql -d mapping -c \"INSERT INTO mapping (ip,username) VALUES('1.2.3.4','test');\"" postgres

It works fine, but when i try from python:

subprocess.run("su -c \"psql -d mapping -c \"INSERT INTO mapping (ip,username) VALUES('1.2.3.4','test');\"\" postgres")

It fails, i have tried different quotation marks and all failing. Could you please help?

tripleee
  • 175,061
  • 34
  • 275
  • 318
user2913139
  • 557
  • 2
  • 5
  • 13
  • You are needing to pass the internal slashes to bash, so try \\\"INSERT......\\\"" postgres..... Notice the backslash-backslash -- the first one escapes the second, the third one escapes the double quote inside the double-quoted command in bash. – Matt Runion Sep 05 '18 at 19:27
  • still the same issue with: subprocess.call("su -c \"psql -d mapping -c \\\"INSERT INTO mapping (ip,username) VALUES('1.2.3.4','test');\\\"\" postgres") – user2913139 Sep 05 '18 at 20:01
  • Instead of calling subprocess.run, use a "print(...)" statement to print out what is getting output. Also, you say it fails -- what error message is being displayed? – Matt Runion Sep 05 '18 at 20:03
  • if i run print() i got he following error: python3 search.py File "search.py", line 49 print('su -c \"psql -d mapping -c \\\"INSERT INTO mapping (ip,username) VALUES('1.2.3.4','test');\\\"\" postgres") ^ SyntaxError: invalid syntax – user2913139 Sep 05 '18 at 20:06
  • when run from subprocess.call i got error: FileNotFoundError: [Errno 2] No such file or directory:............... – user2913139 Sep 05 '18 at 20:07
  • Try this: print("su -c \\\"psql -d mapping -c \\\"INSERT INTO mapping (ip,username) VALUES('1.2.3.4','test');\\\"\\\" postgres") – Matt Runion Sep 05 '18 at 20:08
  • OK, i was getting "No such file or dir" because used just "su", with "/bin/su" it's better, right now i got the error invalid syntax point at '1.2.3.4' part (the same call as original or with \\\\) – user2913139 Sep 05 '18 at 20:11
  • I am not executing that command, but the print statement I sent above matches what you say works on the command line. I have no further way to troubleshoot this as the output from the print statement matches the command you say works directly in Bash. Sorry I can not help further. – Matt Runion Sep 05 '18 at 20:13
  • print command returns invalid syntax pointing to 1.2.3.4: print('/bin/su -c \"psql -d mapping -c \\\"INSERT INTO mapping (ip,username) VALUES('1.2.3.4','test');\\\"\" postgres") . SyntaxError: invalid syntax – user2913139 Sep 05 '18 at 20:15
  • Notice how your print statement and mine differ.....I have added more slashes to mine in my previous comment. – Matt Runion Sep 05 '18 at 20:17
  • OK, i am at the stage where print is working fine, and if i take print results and execute in bash it is working fine. But if i do replace print with subprocess.call it fails with "No such file or directory". – user2913139 Sep 05 '18 at 20:37
  • this is my current call from python: subprocess.call('/bin/su -c \"psql -d mapping -c \\\"INSERT INTO mapping (ip,username) VALUES(\'1.2.3.4\',\'test\');\\\"\" postgres') – user2913139 Sep 05 '18 at 20:37

1 Answers1

2

There are two solutions, depending on whether or not you use the shell from Python. The trivial but inefficient solution is to pass the string with shell=True and basically just add Python quoting around it.

subprocess.run(r'''su -c "psql -d mapping -c \"INSERT INTO mapping (ip,username) VALUES('1.2.3.4','test');\"" postgres''', shell=True,
    # For good measure, you should check its status
    check=True)

More efficiently and perhaps in fact more readably, you can remove the shell from the equation, and split the command into strings yourself.

subprocess.run([
        'su', '-c',
        # The argument to "su -c" should be one string
        # Because we escaped the shell, the double quotes don't need escaping
        '''psql -d mapping -c "INSERT INTO mapping (ip,username) VALUES('1.2.3.4','test');"''',
        'postgres'],
    check=True)

Notice how with shell=True the first argument is a string which gets passed to the shell, whereas without it, you pass a list of tokens directly to the OS-level exec() or (somewhat less straightforwardly on Windows) CreateProcess(). Notice also how in the first instance I used an r'...' string to avoid having Python meddle with the backslashes in the string.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • For more on this, perhaps see also my answer at https://stackoverflow.com/questions/4256107/running-bash-commands-in-python – tripleee Sep 06 '18 at 05:32