#!/bin/env lua -- Basic Unix-style directory listing. -- Demonstrates low-level raw use of a Dir, in order to list even . and .. to -- output. -- -- NOTE: the simplistic argument parser doesn't handle merged options like -ht. -- -- Example uses: -- lua ls.lua -- lua ls.lua -a .. -- lua ls.lua -a -h src -- lua ls.lua -a -t a.dir b.dir c.dir -- -- Supported options: -- -a list hidden files -- -t sort by time, most recent first -- -S sort by size, largest first -- -h print size next to each file in kilobytes (1024) -- -- Author: Lorenzo Cogotti, The DoubleFourteen Code Forge local osx = require 'osx' local io = require 'io' local write = io.write local sep = osx.sep local aflag = false -- list hidden local tflag = false -- sort by time local Sflag = false -- sort by size local hflag = false -- print size, human readable (equivalent to -sh) local function parseargs(...) local args = {} for i = 1,select('#', ...) do local arg = select(i, ...) if arg == '-a' then aflag = true elseif arg == '-t' then tflag, Sflag = true, false elseif arg == '-S' then Sflag, tflag = true, false elseif arg == '-h' then hflag = true else args[#args+1] = arg end end if #args == 0 then args = { "." } -- current directory by default end return args end local function ksize(sz) sz = sz / 1024 if sz > 0 then return ("%.1fK"):format(sz) else return "0" end end local function listfilenames(filenames, bufs, total) table.sort(filenames) -- always sort by name if Sflag then table.sort(filenames, function (a, b) a, b = bufs[a], bufs[b] local asize = a.size or -1 local bsize = b.size or -1 return asize > bsize -- sort by size, largest first end) elseif tflag then table.sort(filenames, function(a, b) a, b = bufs[a], bufs[b] local atime = a.mtime or -1 local btime = b.mtime or -1 return atime > btime -- sort by time, latest first end) end if hflag then write(ksize(total), " total\n") end for _, filename in ipairs(filenames) do local buf = bufs[filename] if hflag then write(ksize(buf.size or 0), " ") end write(filename, "\n") end end local function ls(path) local dir, err = osx.opendir(path) if not dir then io.stderr:write(err, "\n") return end local filenames = {} local bufs = {} local total = 0 while true do :: nextfilename :: local filename, err = dir:readdir() if err then -- Report, but tolerate error io.stderr:write(path, ": ", err, "\n") end if not filename then break -- done with this dir end if filename:sub(1, 1) == '.' and not aflag then goto nextfilename -- skip hidden end -- stat() file, update counters and store for listing local filepath = path..sep..filename local buf, err = osx.stat(filepath) if not buf then io.stderr:write(filepath, ": ", err, "\n") goto nextfilename end total = total + (buf.size or 0) filenames[#filenames+1] = filename bufs[filename] = buf end -- Print file list listfilenames(filenames, bufs, total) dir:close() -- NOTE: could have marked this with end local args = parseargs(...) for _,path in ipairs(args) do ls(path) end