1

I have the following command that I want to execute in Python and store in a variable:

ls -1 var1 2>/dev/null | grep var2 | grep var3 | head -n 1

But I can't get it to work. I tried using subprocess (both 'call' and 'check_output' as well as 'os.system' and nothing worked.. It always gave me an error or a wrong input, while when I execute this command in the shell it works properly.

iulian
  • 5,494
  • 3
  • 29
  • 39
Gambit2007
  • 3,260
  • 13
  • 46
  • 86
  • 6
    BTW, this is in general very bad form, even in native shell -- as discussed in http://mywiki.wooledge.org/ParsingLs -- and doubly so in Python, where there are native tools for iterating over the directory tree. Not all possible filenames *can* be represented in a newline-delimited stream, so there necessarily exist names that `ls` will misrepresent. – Charles Duffy Jun 01 '16 at 16:37
  • 4
    If you want to call a bunch of shell commands, a shell script would be a more appropriate tool than a Python program. If you want to write Python, you should use tools like `os.listdir` and Python's own string matching utilities. – user2357112 Jun 01 '16 at 16:38
  • What Charles Duffy said. Also see the answers to [Why *not* parse `ls`?](http://unix.stackexchange.com/q/128985/88378) on Unix & Linux. – PM 2Ring Jun 01 '16 at 16:49
  • thanks for that guys, i'll definitely keep it in mind. – Gambit2007 Jun 01 '16 at 18:19
  • If you're concerned about script portability you should _definitely_ avoid parsing the output of `ls`! There are many variations of `ls` out there in the wild, and even on the one machine its output can change depending on the settings of various environment variables. – PM 2Ring Jun 01 '16 at 21:37
  • Yes i agree, that is why i replied to treesloth's answer saying i won't end up using it. – Gambit2007 Jun 01 '16 at 21:49

3 Answers3

3

For executing shell commands you'd use the subprocess module.

Usage and examples can be found at: Python Docs: subprocess

The actual python code for calling bash would look like this

import subprocess
task = subprocess.Popen("ls -1 var1 2>/dev/null | grep var2 | grep var3 | head -n 1",
                        shell=True, 
                        stdout=subprocess.PIPE)
directory = task.stdout.read()
print(directory) # result

The recommended way though would to use python to do the directory search. Python listdir() The command for oslistdir could look like this

files = [f for f in os.listdir('.') if re.match(r'[0-9]+.*\.jpg', f)]
treesloth
  • 56
  • 4
  • for this specific case i decided to use python's 'os' module for script portability sake, but your answer is great and will be useful in future tasks, thanks! – Gambit2007 Jun 01 '16 at 18:44
  • With Py3 you can simplify just by using `subprocess.check_output`, given the OP is using `head -n 1` it looks like they just want the first result, so just assign it to a variable. – AChampion Jun 02 '16 at 00:29
1

I don't have any problem when using subprocess :

>>> import subprocess
>>> sub = subprocess.Popen("ls -1 var1 2>/dev/null | grep var2 | grep var3 | head -n 1", shell=True, stdout=subprocess.PIPE)
>>> str = sub.stdout.read()
>>> str
''

You can find additional informations regarding calling shell command while saving the output here.

Hope it'll be helpful.

Community
  • 1
  • 1
3kt
  • 2,543
  • 1
  • 17
  • 29
0

You need to ensure you are executing in a shell, as you are relying on the shell to dispatch the pipes, e.g. (Py>3.1):

import subprocess
var1, var2, var3 = "var1", "var2", "var3"
cmd = "ls -1 {} 2>/dev/null | grep {} | grep {} | head -n 1".format(var1, var2, var3)
result = subprocess.check_output(cmd, shell=True)
AChampion
  • 29,683
  • 4
  • 59
  • 75