1

I have this script, which I have no doubt is flawed:

import fnmatch, os, sys
def findit (rootdir, find, pattern):
    for folder, dirs, files in os.walk(rootdir):
        print (folder)
    for filename in fnmatch.filter(files,pattern):          
        with open(filename) as f:
            s = f.read()
            f.close()
            if find in s :                  
                print(filename)

findit(sys.argv[1], sys.argv[2], sys.argv[3])

when I run it I get Errno2, no such file or directory. BUT the file exists. For instance if I execute it by going: findit.py c:\python "folder" *.py it will work just fine, listing all the *.py files which contain the word "folder". BUT if I go findit.py c:\php\projects1 "include" *.php

as an example I get [Errno2] no such file or directory: 'About.php' (for example). But About.php exists. I don't understand what it's doing, or what I'm doing wrong.

2
  • If you look at any of the examples for os.walk, you'll see that they all do os.path.join(root, name). You need to do the same, for the same reasons. Commented Apr 3, 2013 at 23:39
  • Also, your indentation is wrong; you need the for filename in… loop to be inside the for folders… loop. Otherwise, you're only looking over whichever directory happened to come up last in the walk. Commented Apr 3, 2013 at 23:40

2 Answers 2

2

If you look at any of the examples for os.walk, you'll see that they all do os.path.join(root, name). You need to do that too.

Why? Quoting from the docs:

filenames is a list of the names of the non-directory files in dirpath. Note that the names in the lists contain no path components. To get a full path (which begins with top) to a file or directory in dirpath, do os.path.join(dirpath, name).

If you just use the filename as a path, it's going to look for a file of the same name in the current working directory. If there's no such file, you'll get a FileNotFoundError. If there is such a file, you'll open and read the wrong file. Only if you happen to be looking inside the current working directory will it work.


There's also another major problem in your code: os.walk walks a directory tree recursively, finding all files in the given top directory, or any subdirectory of top, or any subdirectory of… and so on, yielding once for each directory. But you're not doing anything useful with that (except printing out the folders). Instead, you wait until it finishes, and then use the files from whichever directory it happened to reach last.

If you just want to get a flat listing of the files directly in a directory, use os.listdir, not os.walk. (Or maybe use glob.glob instead of explicitly listing everything then filtering with fnmatch.)

On the other hand, if you want to walk the tree, you have to move your second for loop inside the first one.


You've also got a minor problem: You call f.close() inside a with open(…) as f:, which leads to f being closed twice. This is guaranteed to be completely harmless (at least in 2.5+, including 3.x), but it's still a bad idea.


Putting it together, here's a working version of your code:

def findit (rootdir, find, pattern):
    for folder, dirs, files in os.walk(rootdir):
        print (folder)
        for filename in fnmatch.filter(files,pattern):
            pathname = os.path.join(folder, filename)
            with open(pathname) as f:
                s = f.read()
                if find in s:
                    print(pathname)
Sign up to request clarification or add additional context in comments.

2 Comments

@Ron: It's pretty normal to make this many mistakes in a function like this. Eventually, you'll make the same mistakes so many times that you can immediately spot and fix them when the test fails. But you'll never stop making them.
@Ron: I wasn't really talking about you, but about me, and all the people I've worked with in professional and open source projects over cough cough years. Nobody ever stops making simple errors, we just get better at spotting and fixing them. (Which is, when you think about it, why sites like this work.)
1

You are using a relative filename. But your current directory does not contain the file. And you don't want to search there anyway. Use os.path.join(folder, filename) to make an absolute path.

1 Comment

Being in the system PATH isn't relevant to the open function. More likely, it works because it's his current working directory.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.