2

I have linux command like below:

 find /data/*/hr/ -printf "%f: %p: %u: %g %m (%M) \n"

How do i use in python subprocess check_output

I have tried like below but not working

 file_name = "/data/*/%s/" % (filename)
 get_perm = check_output(["find", file_name, "-printf", '\"%f: %p: %u: %g %m (%M) \n\"'])

Error I am getting:

find: ‘/data/*/hr/’: No such file or directory
Traceback (most recent call last):
  File "handover.py", line 90, in <module>
    get_perm = check_output(["find", file_name, "-printf", '\"%f: %p: %u: %g %m (%M) \n\"'])
  File "/usr/lib64/python2.7/subprocess.py", line 573, in check_output
    raise CalledProcessError(retcode, cmd, output=output)
subprocess.CalledProcessError: Command '['find', '/data/*/hr/', '-printf', '"%f: %p: %u: %g %m (%M) \n"']' returned non-zero exit status 1
5
  • You're missing a comma after -printf Commented Sep 10, 2017 at 23:38
  • Do you get any output? Do you get an error (i.e. a CalledProcessError?). If it dumped because it didn't like the -printf"%f: %p:... argument, it should have raised something Commented Sep 10, 2017 at 23:40
  • Python is also translating \n in the string into a literal newline, which might be strange when find gets it. You can also avoid escaping " chars by using ' chars to wrap the string literal in. Commented Sep 10, 2017 at 23:42
  • Edited Post and provide output Commented Sep 10, 2017 at 23:53
  • Possible duplicate of Running shell command from Python and capturing the output Commented Sep 11, 2017 at 2:55

3 Answers 3

2

Finally,

I found below method

cmd = "find /data/*/{}/* -printf \"%f:%p:%u:%g:%m\n\"".format(filename)
info = subprocess.Popen(cmd,stdout=subprocess.PIPE,shell=True)
print info.stdout.read()

This solves my problem

Sign up to request clarification or add additional context in comments.

Comments

0

Your shell will expand the * in /data/*/hr/ when you call on the command line. Calling the function directly via check_output causes find to look for literally the directory /data/*/hr/. You could use the glob module to expand the path before passing to find:

import glob

file_name = "/data/*/%s/" % (filename)
get_perm = check_output(["find"] + glob.glob(file_name) + ["-printf", '\"%f: %p: %u: %g %m (%M) \n\"'])

glob.glob simply produces an array of path names which match the given expression by expanding any *s and some other special characters.

4 Comments

Hi Michael, It works fine.. But problem is filename "/data/*/fin/" . If fin does not exist. It will list other values. If fin does not exit. I expect to get no such file or directory error
@gopinara It will list other files because you have a trailing slash, which the find command interprets as you indicating you want to list all of the files/directories contained within /fin/. Try removing the trailing slash. You can also specify a type to find to limit the results to only files or directories, like, find /data/*/fin -type f. Also, the first argument to find is usually the directory which you want to search within for a file or directory. Maybe you want something like find /data/*/fin -type f -name your_file_name.ext
I tried removing slash and adding -type d..same result
You may just want to check if glob.glob(file_name) produces an empty array and if so, don't run the command at all.
0

You are getting this error because the specified file does not exist. If you run the command directly in a shell, you will get the same response.

For example, the following works as expected:

import subprocess
import os

file_name = os.path.join(os.getcwd(), 'test.txt')
with open(file_name, 'w') as f:
    f.write('hello world')

get_perm = subprocess.check_output([
    "find",
     file_name,
     "-printf",
    '"%f: %p: %u: %g %m (%M) \n"'
    ], shell=True)

print(get_perm)
os.remove(file_name)

According to the docs:

If the return code [from subprocess.check_output] was non-zero it raises a CalledProcessError. The CalledProcessError object will have the return code in the returncode attribute and any output in the output attribute.

I recommend you wrap your check_output call in a try..except, and catch the CalledProcessError.

Alternatively, if you really don't want to deal with the exception, you could instead execute the command:

x=$(find ~/data/*/hr/ -printf "%f: %p: %u: %g %m (%M) \n" 2>/dev/null || true) && echo $x

This will never return nonzero and will only ever contain output if the file exists.

Edit As Michael pointed out, the '*' is not getting expanded. However, if you set shell=True, it will. Try modifying your command as follows:

 file_name = "/data/*/%s/" % (filename)
 get_perm = check_output(["find", file_name, "-printf", '"%f: %p: %u: %g %m (%M) \n"'], shell=True)

3 Comments

While it's true that the file isn't found, the problem is likely that the * in the path should be expanded.
@MichaelMior Good catch. If you set shell=True, it will expand that the splat.
You're right. Adding shell=True is an easy solution :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.