How to get list of directories in Lua

82,039

Solution 1

Take the easy way, install lfs. Then use the following constructs to find what you need:

require'lfs'
for file in lfs.dir[[C:\Program Files]] do
    if lfs.attributes(file,"mode") == "file" then print("found file, "..file)
    elseif lfs.attributes(file,"mode")== "directory" then print("found dir, "..file," containing:")
        for l in lfs.dir("C:\\Program Files\\"..file) do
             print("",l)
        end
    end
end

notice that a backslash equals [[\]] equals "\\", and that in windows / is also allowed if not used on the cmd itself (correct me if I'm wrong on this one).

Solution 2

I hate having to install libraries (especially those that want me to use installer packages to install them). If you're looking for a clean solution for a directory listing on an absolute path in Lua, look no further.

Building on the answer that sylvanaar provided, I created a function that returns an array of all the files for a given directory (absolute path required). This is my preferred implementation, as it works on all my machines.

-- Lua implementation of PHP scandir function
function scandir(directory)
    local i, t, popen = 0, {}, io.popen
    local pfile = popen('ls -a "'..directory..'"')
    for filename in pfile:lines() do
        i = i + 1
        t[i] = filename
    end
    pfile:close()
    return t
end

If you are using Windows, you'll need to have a bash client installed so that the 'ls' command will work - alternately, you can use the dir command that sylvanaar provided:

'dir "'..directory..'" /b /ad'

Solution 3

I don't like installing libraries either and am working on an embedded device with less memory power then a pc. I found out that using 'ls' command lead to an out of memory. So I created a function that uses 'find' to solve the problem.

This way it was possible to keep memory usage steady and loop all the 30k files.

function dirLookup(dir)
   local p = io.popen('find "'..dir..'" -type f')  --Open directory look for files, save data in p. By giving '-type f' as parameter, it returns all files.     
   for file in p:lines() do                         --Loop through all files
       print(file)       
   end
end

Solution 4

 for dir in io.popen([[dir "C:\Program Files\" /b /ad]]):lines() do print(dir) end

*For Windows

Outputs:

Adobe
Bitcasa
Bonjour
Business Objects
Common Files
DVD Maker
IIS
Internet Explorer
iPod
iTunes
Java
Microsoft Device Emulator
Microsoft Help Viewer
Microsoft IntelliPoint
Microsoft IntelliType Pro
Microsoft Office
Microsoft SDKs
Microsoft Security Client
Microsoft SQL Server
Microsoft SQL Server Compact Edition
Microsoft Sync Framework
Microsoft Synchronization Services
Microsoft Visual Studio 10.0
Microsoft Visual Studio 9.0
Microsoft.NET
MSBuild
...

Each time through the loop you are given a new folder name. I chose to print it as an example.

Solution 5

IIRC, getting the directory listing isn't possible with stock Lua. You need to write some glue code yourself, or use LuaFileSystem. The latter is most likely the path of least resistance for you. A quick scan of the docs shows lfs.dir() which will provide you with an iterator you can use to get the directories you are looking for. At that point, you can then do your string comparison to get the specific directories you need.

Share:
82,039
Admin
Author by

Admin

Updated on December 17, 2020

Comments

  • Admin
    Admin over 3 years

    I need a list of directory in LUA

    Suppose I have a directory path as "C:\Program Files"

    I need a list of all the folders in that particular path and how to search any particular folder in that list.

    Example

    Need a list of all the folder in path "C:\Program Files"

    Below are folder name in the above path

    1. test123

    2. test4567

    3. folder 123

    4. folder 456

    5. folder 456 789

      Need to get the above in a list and then have to search for a particular string like folder 456 in folder 456 789 only.

    Have Tried below code. Something I am missing below:-

    local function Loc_Lines( str )
    --
    local ret= {}   -- 0 lines
    
    while str do
        local _,_,line,tail= string.find( str, "(.-)\n(.+)" )
        table.insert( ret, line or str )
        str= tail
      Print (str)
    end
    
    return ret
    end
    
    
    local function Loc_ShellCommand( cmd )
    --
    local str= nil
    
        --
        local f= io.popen( cmd )    -- no command still returns a handle :(
         if f then
    
            str= f:read'*a'
        Print(str)
            f:close()
        end
        
        if str=="" then   -- take no output as a failure (we can't tell..)
        Print("hi")
            str= nil
        end
     
    -- Remove terminating linefeed, if any (eases up one-line analysis)
    --
    if str then
        if string.sub( str, -1 ) == '\n' then
            str= string.sub( str, 1, -2 )
        end
    end
    
    return str
     end
    
    
     local function Loc_DirCmd( cmd )
    
     Print(cmd)
    
      local str= Loc_ShellCommand( cmd )
    
    
    
     return Loc_Lines(str)
     end
    
    
    local function Loc_DirList( dirname )
    
     local ret= {}
      
        local lookup= {}
    
       local tbl= Loc_DirCmd( "dir /AD /B "..dirname )   -- only dirs
    
        -- Add slash to every dir line
        --
        for i,v in ipairs(tbl) do
            table.insert( ret, v..'\\' )
            lookup[v]= true
        end       
    
        
        -- Return with forward slashes
        --
        if true then
            for i=1,table.getn(ret) do
                ret[i]= string.gsub( ret[i], '\\', '/' )
         Print (ret[i])
            end
        end
      
    
       return ret
     end
    
    
     Loc_DirList("C:\\Program Files\\")
    
  • Admin
    Admin over 13 years
    Please check it seems I am missing something while getting the list.
  • Admin
    Admin over 13 years
    Tired what you are suggesting something I am missing here
  • Glenn McAllister
    Glenn McAllister over 13 years
    (Question was updated to include the code the OP is using, which wasn't around when I wrote my answer.) Fair point, I neglected to mention you could shell out with io.popen(). I assumed you were looking for a generic way to do this, not a Windows specific way. I don't have a Windows box to try this out on. Perhaps you could update your question with the results you get, and the results you expected to get.
  • Glenn McAllister
    Glenn McAllister over 13 years
    @che - from what I can see, you haven't tried what I suggested, you chose to go down the route of using a platform specific option. As I already indicated, I don't have a Windows box with Lua to try and track down your problem for you, particularly since you haven't provided the output you get, and the output you expect.
  • Admin
    Admin over 13 years
    This is the Anwer I was looking for can be done with require "lfs" hFile = io.popen('dir /a:d /b "C:\\Program Files\\"') line = hFile:read('*l') while (line ~= nil) do Print(line) line = hFile:read('*l') end
  • Mark
    Mark about 11 years
    Just a note: Your code gives you all files; the dir command as given gives you just directories. To get all files, just use dir <path> /b (leave off the /ad, which specifies only directories.)
  • RandyGaul
    RandyGaul over 10 years
    You can just recompile a lua library with lfs.h and lfs.c within them. This is what I did to "install" lfs.
  • Daniel Jordi
    Daniel Jordi over 8 years
    this seems to be the best answer with no libraries, does it work in windows?
  • RainingChain
    RainingChain over 8 years
    Note: To get list of files, only use /b instead of /b /ad.
  • ulmangt
    ulmangt over 8 years
    The call to popen('ls -a "'..directory..'"') returns a file handle which your function does not close. So as written your implementation leaks open file handles. I submitted a simple edit/fix.
  • Roman Shapovalov
    Roman Shapovalov over 8 years
    @DanielJordi I don’t think so; in Windows the command find is a counterpart of grep, not the file finder.
  • Roman Shapovalov
    Roman Shapovalov over 8 years
    This function will traverse the tree recursively, not just list the directory.
  • C. Wang
    C. Wang about 8 years
    I found paths.files(currentPath) will return an unsorted result. How to sort them. Is there code like for file in sort(paths.files(currentPath)) do?
  • Amir
    Amir about 8 years
    @C.Wang Please check my answer again. I updated it with the suitable code for your task
  • Jesse Chisholm
    Jesse Chisholm about 8 years
    Because of my odd needs, I used the inner command find . -name "*.lua" -print | grep -v "/build/" to get the list of non-generated scripts. I further filter that list before using it.
  • Micheal Johnson
    Micheal Johnson about 8 years
    Don't parse ls.
  • Heinrich Hartmann
    Heinrich Hartmann over 7 years
    This break horribly as when directory names contain single quotes (and maybe other nasty characters). Remember POSIX file names are just byte strings.
  • Solomon Ucko
    Solomon Ucko about 5 years
    Don't parse the output of ls. Use find -maxdepth 1 -print0 instead. The problem with ls is that there are many inconsistencies between implementations, and few, if any, allow using a separator that the file names cannot contain (they can contain newlines!), most commonly the null byte, but a slash could probably work too.
  • Solomon Ucko
    Solomon Ucko about 5 years
    To properly handle filenames containing newlines, use find ... -print0 and split on null bytes. You might also want to add -maxdepth 1 to avoid recursing into subdirectories.
  • Jay Elston
    Jay Elston almost 3 years
    To get this to work for me, I had to use a file with a fully qualified path name. That is, lfs.attributes("C:\\Program Files\\" .. file, "mode") Also, you should consider filtering out "." and "..", at least on Linux systems.