shell tools: globbing
This commit is contained in:
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
title = 'Shell utilities',
|
|
||||||
repository = 'kepler155c/opus-apps/{{OPUS_BRANCH}}/openos',
|
|
||||||
description = [[Experimental!
|
|
||||||
Utilties for shell: grep, cat, touch, etc ]],
|
|
||||||
licence = 'MIT',
|
|
||||||
}
|
|
||||||
331
openos/tree.lua
331
openos/tree.lua
@@ -1,331 +0,0 @@
|
|||||||
local computer = require("openos.computer")
|
|
||||||
local shell = require("openos.shell")
|
|
||||||
local fs = require("openos.filesystem")
|
|
||||||
local tx = require("openos.transforms")
|
|
||||||
local text = require("openos.text")
|
|
||||||
|
|
||||||
local args, opts = shell.parse(...)
|
|
||||||
|
|
||||||
local function die(...)
|
|
||||||
io.stderr:write(...)
|
|
||||||
os.exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
do -- handle cli
|
|
||||||
if opts.help then
|
|
||||||
print([[Usage: tree [OPTION]... [FILE]...
|
|
||||||
-a, --all do not ignore entries starting with .
|
|
||||||
--full-time with -l, print time in full iso format
|
|
||||||
-h, --human-readable with -l, print human readable sizes
|
|
||||||
--si likewise, but use powers of 1000 not 1024
|
|
||||||
--level=LEVEL descend only LEVEL directories deep
|
|
||||||
--color=WHEN WHEN can be
|
|
||||||
auto - colorize output only if writing to a tty,
|
|
||||||
always - always colorize output,
|
|
||||||
never - never colorize output; (default: auto)
|
|
||||||
-l use a long listing format
|
|
||||||
-f print the full path prefix for each file
|
|
||||||
-i do not print indentation lines
|
|
||||||
-p append "/" indicator to directories
|
|
||||||
-Q, --quote quote filenames with double quotes
|
|
||||||
-r, --reverse reverse order while sorting
|
|
||||||
-S sort by file size
|
|
||||||
-t sort by modification type, newest first
|
|
||||||
-X sort alphabetically by entry extension
|
|
||||||
-C do not count files and directories
|
|
||||||
-R count root directories like other files
|
|
||||||
--help print this help and exit]])
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
if #args == 0 then
|
|
||||||
table.insert(args, ".")
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.level = tonumber(opts.level) or math.huge
|
|
||||||
if opts.level < 1 then
|
|
||||||
die("Invalid level, must be greater than 0")
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.color = opts.color or "auto"
|
|
||||||
if opts.color == "auto" then
|
|
||||||
opts.color = io.stdout.tty and "always" or "never"
|
|
||||||
end
|
|
||||||
|
|
||||||
if opts.color ~= "always" and opts.color ~= "never" then
|
|
||||||
die("Invalid value for --color=WHEN option; WHEN should be auto, always or never")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local lastYield = computer.uptime()
|
|
||||||
local function yieldopt()
|
|
||||||
if computer.uptime() - lastYield > 2 then
|
|
||||||
lastYield = computer.uptime()
|
|
||||||
os.sleep(0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function peekable(iterator, state, var1)
|
|
||||||
local nextItem = {iterator(state, var1)}
|
|
||||||
|
|
||||||
return setmetatable({
|
|
||||||
peek = function()
|
|
||||||
return table.unpack(nextItem)
|
|
||||||
end
|
|
||||||
}, {
|
|
||||||
__call = coroutine.wrap(function()
|
|
||||||
while true do
|
|
||||||
local item = nextItem
|
|
||||||
nextItem = {iterator(state, nextItem[1])}
|
|
||||||
coroutine.yield(table.unpack(item))
|
|
||||||
if nextItem[1] == nil then break end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
local function filter(entry)
|
|
||||||
return opts.a or entry:sub(1, 1) ~= "."
|
|
||||||
end
|
|
||||||
|
|
||||||
local function stat(path)
|
|
||||||
local st = {}
|
|
||||||
st.path = path
|
|
||||||
st.name = fs.name(path) or "/"
|
|
||||||
st.sortName = st.name:gsub("^%.","")
|
|
||||||
st.time = fs.lastModified(path)
|
|
||||||
st.isLink = fs.isLink(path)
|
|
||||||
st.isDirectory = fs.isDirectory(path)
|
|
||||||
st.size = st.isLink and 0 or fs.size(path)
|
|
||||||
st.extension = st.name:match("(%.[^.]+)$") or ""
|
|
||||||
st.fs = fs.get(path)
|
|
||||||
return st
|
|
||||||
end
|
|
||||||
|
|
||||||
local colorize
|
|
||||||
if opts.color == "always" then
|
|
||||||
-- from /lib/core/full_ls.lua
|
|
||||||
local colors = tx.foreach(text.split(os.getenv("LS_COLORS") or "", {":"}, true), function(e)
|
|
||||||
local parts = text.split(e, {"="}, true)
|
|
||||||
return parts[2], parts[1]
|
|
||||||
end)
|
|
||||||
|
|
||||||
function colorize(stat)
|
|
||||||
return stat.isLink and colors.ln or
|
|
||||||
stat.isDirectory and colors.di or
|
|
||||||
colors["*" .. stat.extension] or
|
|
||||||
colors.fi
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function list(path)
|
|
||||||
return coroutine.wrap(function()
|
|
||||||
local l = {}
|
|
||||||
for entry in fs.list(path) do
|
|
||||||
if filter(entry) then
|
|
||||||
table.insert(l, stat(fs.concat(path, entry)))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if opts.S then
|
|
||||||
table.sort(l, function(a, b)
|
|
||||||
return a.size < b.size
|
|
||||||
end)
|
|
||||||
elseif opts.t then
|
|
||||||
table.sort(l, function(a, b)
|
|
||||||
return a.time < b.time
|
|
||||||
end)
|
|
||||||
elseif opts.X then
|
|
||||||
table.sort(l, function(a, b)
|
|
||||||
return a.extension < b.extension
|
|
||||||
end)
|
|
||||||
else
|
|
||||||
table.sort(l, function(a, b)
|
|
||||||
return a.sortName < b.sortName
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
for i = opts.r and #l or 1, opts.r and 1 or #l, opts.r and -1 or 1 do
|
|
||||||
coroutine.yield(l[i])
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function digRoot(rootPath)
|
|
||||||
coroutine.yield(stat(rootPath), {})
|
|
||||||
|
|
||||||
if not fs.isDirectory(rootPath) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local iterStack = {peekable(list(rootPath))}
|
|
||||||
local pathStack = {rootPath}
|
|
||||||
local levelStack = {not not iterStack[#iterStack]:peek()}
|
|
||||||
|
|
||||||
|
|
||||||
repeat
|
|
||||||
local entry = iterStack[#iterStack]()
|
|
||||||
|
|
||||||
if entry then
|
|
||||||
levelStack[#levelStack] = not not iterStack[#iterStack]:peek()
|
|
||||||
|
|
||||||
local path = fs.concat(fs.concat(table.unpack(pathStack)), entry.name)
|
|
||||||
|
|
||||||
coroutine.yield(entry, levelStack)
|
|
||||||
|
|
||||||
if entry.isDirectory and opts.level > #levelStack then
|
|
||||||
table.insert(iterStack, peekable(list(path)))
|
|
||||||
table.insert(pathStack, entry.name)
|
|
||||||
table.insert(levelStack, not not iterStack[#iterStack]:peek())
|
|
||||||
end
|
|
||||||
else
|
|
||||||
table.remove(iterStack)
|
|
||||||
table.remove(pathStack)
|
|
||||||
table.remove(levelStack)
|
|
||||||
end
|
|
||||||
until #iterStack == 0
|
|
||||||
end
|
|
||||||
|
|
||||||
local function dig(roots)
|
|
||||||
return coroutine.wrap(function()
|
|
||||||
for _, root in ipairs(roots) do
|
|
||||||
digRoot(root)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function nod(n) -- from /lib/core/full_ls.lua
|
|
||||||
return n and (tostring(n):gsub("(%.[0-9]+)0+$","%1")) or "0"
|
|
||||||
end
|
|
||||||
|
|
||||||
local function formatFSize(size) -- from /lib/core/full_ls.lua
|
|
||||||
if not opts.h and not opts["human-readable"] and not opts.si then
|
|
||||||
return tostring(size)
|
|
||||||
end
|
|
||||||
|
|
||||||
local sizes = {"", "K", "M", "G"}
|
|
||||||
local unit = 1
|
|
||||||
local power = opts.si and 1000 or 1024
|
|
||||||
|
|
||||||
while size > power and unit < #sizes do
|
|
||||||
unit = unit + 1
|
|
||||||
size = size / power
|
|
||||||
end
|
|
||||||
|
|
||||||
return nod(math.floor(size*10)/10)..sizes[unit]
|
|
||||||
end
|
|
||||||
|
|
||||||
local function pad(txt) -- from /lib/core/full_ls.lua
|
|
||||||
txt = tostring(txt)
|
|
||||||
return #txt >= 2 and txt or "0" .. txt
|
|
||||||
end
|
|
||||||
|
|
||||||
local function formatTime(epochms) -- from /lib/core/full_ls.lua
|
|
||||||
local month_names = {"January","February","March","April","May","June",
|
|
||||||
"July","August","September","October","November","December"}
|
|
||||||
|
|
||||||
if epochms == 0 then return "" end
|
|
||||||
|
|
||||||
local d = os.date("*t", epochms)
|
|
||||||
local day, hour, min, sec = nod(d.day), pad(nod(d.hour)), pad(nod(d.min)), pad(nod(d.sec))
|
|
||||||
|
|
||||||
if opts["full-time"] then
|
|
||||||
return string.format("%s-%s-%s %s:%s:%s ", d.year, pad(nod(d.month)), pad(day), hour, min, sec)
|
|
||||||
else
|
|
||||||
return string.format("%s %+2s %+2s:%+2s ", month_names[d.month]:sub(1,3), day, hour, pad(min))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function writeEntry(entry, levelStack)
|
|
||||||
for i, hasNext in ipairs(levelStack) do
|
|
||||||
if opts.i then break end
|
|
||||||
|
|
||||||
if i == #levelStack then
|
|
||||||
if hasNext then
|
|
||||||
io.write("├── ")
|
|
||||||
else
|
|
||||||
io.write("└── ")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if hasNext then
|
|
||||||
io.write("│ ")
|
|
||||||
else
|
|
||||||
io.write(" ")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if opts.l then
|
|
||||||
io.write("[")
|
|
||||||
|
|
||||||
io.write(entry.isDirectory and "d" or entry.isLink and "l" or "f", "-")
|
|
||||||
io.write("r", entry.fs.isReadOnly() and "-" or "w", " ")
|
|
||||||
|
|
||||||
io.write(formatFSize(entry.size), " ")
|
|
||||||
|
|
||||||
io.write(formatTime(entry.time))
|
|
||||||
io.write("] ")
|
|
||||||
end
|
|
||||||
|
|
||||||
if opts.Q then io.write('"') end
|
|
||||||
|
|
||||||
if opts.color == "always" then
|
|
||||||
io.write("\27[" .. colorize(entry) .. "m")
|
|
||||||
end
|
|
||||||
|
|
||||||
if opts.f then
|
|
||||||
io.write(entry.path)
|
|
||||||
else
|
|
||||||
io.write(entry.name)
|
|
||||||
end
|
|
||||||
|
|
||||||
if opts.color == "always" then
|
|
||||||
io.write("\27[0m")
|
|
||||||
end
|
|
||||||
|
|
||||||
if opts.p and entry.isDirectory then
|
|
||||||
io.write("/")
|
|
||||||
end
|
|
||||||
|
|
||||||
if opts.Q then io.write('"') end
|
|
||||||
io.write("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
local function writeCount(dirs, files)
|
|
||||||
io.write("\n")
|
|
||||||
io.write(dirs, " director", dirs == 1 and "y" or "ies")
|
|
||||||
io.write(", ")
|
|
||||||
io.write(files, " file", files == 1 and "" or "s")
|
|
||||||
io.write("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
local dirs, files = 0, 0
|
|
||||||
|
|
||||||
local roots = {}
|
|
||||||
for _, arg in ipairs(args) do
|
|
||||||
local path = shell.resolve(arg)
|
|
||||||
local real, reason = fs.realPath(path)
|
|
||||||
if not real then
|
|
||||||
die("cannot access ", path, ": ", reason or "unknown error")
|
|
||||||
elseif not fs.exists(path) then
|
|
||||||
die("cannot access ", path, ":", "No such file or directory")
|
|
||||||
else
|
|
||||||
table.insert(roots, real)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for entry, levelStack in dig(roots) do
|
|
||||||
if opts.R or #levelStack > 0 then
|
|
||||||
if entry.isDirectory then
|
|
||||||
dirs = dirs + 1
|
|
||||||
else
|
|
||||||
files = files + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
writeEntry(entry, levelStack)
|
|
||||||
yieldopt()
|
|
||||||
end
|
|
||||||
|
|
||||||
if not opts.C then
|
|
||||||
writeCount(dirs, files)
|
|
||||||
end
|
|
||||||
|
|
||||||
7
shellex/.package
Normal file
7
shellex/.package
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
title = 'Shell utilities',
|
||||||
|
repository = 'kepler155c/opus-apps/{{OPUS_BRANCH}}/shellex',
|
||||||
|
description = [[Experimental!
|
||||||
|
Linux style shell commands: grep, cat, touch, df, etc ]],
|
||||||
|
licence = 'MIT',
|
||||||
|
}
|
||||||
50
shellex/apis/glob.lua
Normal file
50
shellex/apis/glob.lua
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
local GtoP = require('shellex.globtopattern')
|
||||||
|
|
||||||
|
local Glob = { }
|
||||||
|
|
||||||
|
local fs = _G.fs
|
||||||
|
|
||||||
|
local function splitpath(path)
|
||||||
|
local parts = { }
|
||||||
|
for match in string.gmatch(path, "[^/]+") do
|
||||||
|
table.insert(parts, match)
|
||||||
|
end
|
||||||
|
return parts
|
||||||
|
end
|
||||||
|
|
||||||
|
function Glob.matches(path, spec)
|
||||||
|
local t = { }
|
||||||
|
local ss = splitpath(spec)
|
||||||
|
local abs = string.sub(spec, 1, 1) == '/'
|
||||||
|
|
||||||
|
local function dirMatches(dir, i)
|
||||||
|
local files = fs.list(dir)
|
||||||
|
local s = GtoP.globtopattern(ss[i])
|
||||||
|
|
||||||
|
for _, f in pairs(files) do
|
||||||
|
if f:match(s) then
|
||||||
|
local fp = fs.combine(dir, f)
|
||||||
|
if not ss[i + 1] then
|
||||||
|
table.insert(t, '/' .. fp)
|
||||||
|
elseif ss[i + 1] and fs.isDir(fp) then
|
||||||
|
dirMatches(fp, i + 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
path = '/' .. fs.combine('', path) -- normalize
|
||||||
|
|
||||||
|
dirMatches(abs and '' or path, 1)
|
||||||
|
|
||||||
|
if not abs then
|
||||||
|
local len = path == '/' and #path + 1 or #path + 2
|
||||||
|
for k, v in pairs(t) do
|
||||||
|
t[k] = v:sub(len)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
return Glob
|
||||||
119
shellex/apis/globtopattern.lua
Normal file
119
shellex/apis/globtopattern.lua
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
-- see: https://github.com/davidm/lua-glob-pattern
|
||||||
|
local M = {_TYPE='module', _NAME='globtopattern', _VERSION='0.2.1.20120406'}
|
||||||
|
|
||||||
|
function M.globtopattern(g)
|
||||||
|
-- Some useful references:
|
||||||
|
-- - apr_fnmatch in Apache APR. For example,
|
||||||
|
-- http://apr.apache.org/docs/apr/1.3/group__apr__fnmatch.html
|
||||||
|
-- which cites POSIX 1003.2-1992, section B.6.
|
||||||
|
|
||||||
|
local p = "^" -- pattern being built
|
||||||
|
local i = 0 -- index in g
|
||||||
|
local c -- char at index i in g.
|
||||||
|
|
||||||
|
-- unescape glob char
|
||||||
|
local function unescape()
|
||||||
|
if c == '\\' then
|
||||||
|
i = i + 1; c = g:sub(i,i)
|
||||||
|
if c == '' then
|
||||||
|
p = '[^]'
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- escape pattern char
|
||||||
|
local function escape(c)
|
||||||
|
return c:match("^%w$") and c or '%' .. c
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Convert tokens at end of charset.
|
||||||
|
local function charset_end()
|
||||||
|
while 1 do
|
||||||
|
if c == '' then
|
||||||
|
p = '[^]'
|
||||||
|
return false
|
||||||
|
elseif c == ']' then
|
||||||
|
p = p .. ']'
|
||||||
|
break
|
||||||
|
else
|
||||||
|
if not unescape() then break end
|
||||||
|
local c1 = c
|
||||||
|
i = i + 1; c = g:sub(i,i)
|
||||||
|
if c == '' then
|
||||||
|
p = '[^]'
|
||||||
|
return false
|
||||||
|
elseif c == '-' then
|
||||||
|
i = i + 1; c = g:sub(i,i)
|
||||||
|
if c == '' then
|
||||||
|
p = '[^]'
|
||||||
|
return false
|
||||||
|
elseif c == ']' then
|
||||||
|
p = p .. escape(c1) .. '%-]'
|
||||||
|
break
|
||||||
|
else
|
||||||
|
if not unescape() then break end
|
||||||
|
p = p .. escape(c1) .. '-' .. escape(c)
|
||||||
|
end
|
||||||
|
elseif c == ']' then
|
||||||
|
p = p .. escape(c1) .. ']'
|
||||||
|
break
|
||||||
|
else
|
||||||
|
p = p .. escape(c1)
|
||||||
|
i = i - 1 -- put back
|
||||||
|
end
|
||||||
|
end
|
||||||
|
i = i + 1; c = g:sub(i,i)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Convert tokens in charset.
|
||||||
|
local function charset()
|
||||||
|
i = i + 1; c = g:sub(i,i)
|
||||||
|
if c == '' or c == ']' then
|
||||||
|
p = '[^]'
|
||||||
|
return false
|
||||||
|
elseif c == '^' or c == '!' then
|
||||||
|
i = i + 1; c = g:sub(i,i)
|
||||||
|
if c == ']' then
|
||||||
|
-- ignored
|
||||||
|
else
|
||||||
|
p = p .. '[^'
|
||||||
|
if not charset_end() then return false end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
p = p .. '['
|
||||||
|
if not charset_end() then return false end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Convert tokens.
|
||||||
|
while 1 do
|
||||||
|
i = i + 1; c = g:sub(i,i)
|
||||||
|
if c == '' then
|
||||||
|
p = p .. '$'
|
||||||
|
break
|
||||||
|
elseif c == '?' then
|
||||||
|
p = p .. '.'
|
||||||
|
elseif c == '*' then
|
||||||
|
p = p .. '.*'
|
||||||
|
elseif c == '[' then
|
||||||
|
if not charset() then break end
|
||||||
|
elseif c == '\\' then
|
||||||
|
i = i + 1; c = g:sub(i,i)
|
||||||
|
if c == '' then
|
||||||
|
p = p .. '\\$'
|
||||||
|
break
|
||||||
|
end
|
||||||
|
p = p .. escape(c)
|
||||||
|
else
|
||||||
|
p = p .. escape(c)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return p
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
local unicode = require("openos.unicode")
|
local unicode = require("shellex.unicode")
|
||||||
local tx = require("openos.transforms")
|
local tx = require("shellex.transforms")
|
||||||
|
|
||||||
local text = {}
|
local text = {}
|
||||||
text.internal = {}
|
text.internal = {}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
local fs = require("openos.filesystem")
|
local fs = require("shellex.filesystem")
|
||||||
local shell = require("openos.shell")
|
local glob = require('shellex.glob')
|
||||||
local text = require("openos.text")
|
local shell = require("shellex.shell")
|
||||||
|
local text = require("shellex.text")
|
||||||
local lib = {}
|
local lib = {}
|
||||||
|
|
||||||
local function perr(ops, format, ...)
|
local function perr(ops, format, ...)
|
||||||
@@ -236,28 +237,31 @@ function lib.batch(args, options)
|
|||||||
end
|
end
|
||||||
local originalToIsDir = fs.isDirectory(ok)
|
local originalToIsDir = fs.isDirectory(ok)
|
||||||
|
|
||||||
for _, fromArg in ipairs(args) do
|
for _, arg in ipairs(args) do
|
||||||
-- a "contents of" copy is where src path ends in . or ..
|
local files = glob.matches(shell.getWorkingDirectory(), arg)
|
||||||
-- a source path ending with . is not sufficient - could be the source filename
|
for _, fromArg in pairs(files) do
|
||||||
local contents_of
|
-- a "contents of" copy is where src path ends in . or ..
|
||||||
contents_of, ok = contents_check(fromArg, options, true)
|
-- a source path ending with . is not sufficient - could be the source filename
|
||||||
if ok then
|
local contents_of
|
||||||
-- we do not append fromPath name to toPath in case of contents_of copy
|
contents_of, ok = contents_check(fromArg, options, true)
|
||||||
local toPath = toArg
|
if ok then
|
||||||
if contents_of and options.cmd == "mv" then
|
-- we do not append fromPath name to toPath in case of contents_of copy
|
||||||
perr(options, "invalid move path '%s'", fromArg)
|
local toPath = toArg
|
||||||
else
|
if contents_of and options.cmd == "mv" then
|
||||||
if not contents_of and originalToIsDir then
|
perr(options, "invalid move path '%s'", fromArg)
|
||||||
local fromName = fs.name(fromArg)
|
else
|
||||||
if fromName then
|
if not contents_of and originalToIsDir then
|
||||||
toPath = toPath .. "/" .. fromName
|
local fromName = fs.name(fromArg)
|
||||||
|
if fromName then
|
||||||
|
toPath = toPath .. "/" .. fromName
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
local result, reason = lib.recurse(fromArg, toPath, options, origin, true)
|
local result, reason = lib.recurse(fromArg, toPath, options, origin, true)
|
||||||
|
|
||||||
if not result then
|
if not result then
|
||||||
perr(options, reason)
|
perr(options, reason)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
local lib={}
|
local lib={}
|
||||||
lib.internal={}
|
lib.internal={}
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
local shell = require("openos.shell")
|
local shell = require("shellex.shell")
|
||||||
local fs = require("openos.filesystem")
|
local fs = require("shellex.filesystem")
|
||||||
|
|
||||||
local args = shell.parse(...)
|
local args = shell.parse(...)
|
||||||
local ec = 0
|
local ec = 0
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
local shell = require("openos.shell")
|
local shell = require("shellex.shell")
|
||||||
local transfer = require("openos.transfer")
|
local transfer = require("shellex.transfer")
|
||||||
|
|
||||||
local args, options = shell.parse(...)
|
local args, options = shell.parse(...)
|
||||||
options.h = options.h or options.help
|
options.h = options.h or options.help
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
local fs = require("openos.filesystem")
|
local fs = require("shellex.filesystem")
|
||||||
local shell = require("openos.shell")
|
local shell = require("shellex.shell")
|
||||||
local text = require("openos.text")
|
local text = require("shellex.text")
|
||||||
|
|
||||||
local args, options = shell.parse(...)
|
local args, options = shell.parse(...)
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
local tty = require("openos.tty")
|
local tty = require("shellex.tty")
|
||||||
|
|
||||||
local args = {...}
|
local args = {...}
|
||||||
local gpu = tty.gpu()
|
local gpu = tty.gpu()
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
local shell = require("openos.shell")
|
local fs = require("shellex.filesystem")
|
||||||
local fs = require("openos.filesystem")
|
local glob = require('shellex.glob')
|
||||||
|
local shell = require("shellex.shell")
|
||||||
|
|
||||||
local args, options = shell.parse(...)
|
local args, options = shell.parse(...)
|
||||||
if #args == 0 then
|
if #args == 0 then
|
||||||
@@ -107,22 +108,24 @@ local function visitor(rpath)
|
|||||||
end
|
end
|
||||||
|
|
||||||
for _,arg in ipairs(args) do
|
for _,arg in ipairs(args) do
|
||||||
local path = shell.resolve(arg)
|
local files = glob.matches(shell.getWorkingDirectory(), arg)
|
||||||
|
for _, v in pairs(files) do
|
||||||
if not fs.exists(path) then
|
local path = shell.resolve(v)
|
||||||
io.stderr:write(string.format("du: cannot access '%s': no such file or directory\n", arg))
|
if not fs.exists(path) then
|
||||||
return 1
|
io.stderr:write(string.format("du: cannot access '%s': no such file or directory\n", v))
|
||||||
else
|
return 1
|
||||||
if fs.isDirectory(path) then
|
|
||||||
local total = visitor(arg)
|
|
||||||
|
|
||||||
if bSummary then
|
|
||||||
printSize(total, arg)
|
|
||||||
end
|
|
||||||
elseif fs.isLink(path) then
|
|
||||||
printSize(0, arg)
|
|
||||||
else
|
else
|
||||||
printSize(fs.size(path), arg)
|
if fs.isDirectory(path) then
|
||||||
|
local total = visitor(v)
|
||||||
|
|
||||||
|
if bSummary then
|
||||||
|
printSize(total, v)
|
||||||
|
end
|
||||||
|
elseif fs.isLink(path) then
|
||||||
|
printSize(0, v)
|
||||||
|
else
|
||||||
|
printSize(fs.size(path), v)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
local shell = require("openos.shell")
|
local shell = require("shellex.shell")
|
||||||
local fs = require("openos.filesystem")
|
local fs = require("shellex.filesystem")
|
||||||
local text = require("openos.text")
|
local text = require("shellex.text")
|
||||||
|
|
||||||
local USAGE =
|
local USAGE =
|
||||||
[===[Usage: find [path] [--type=[dfs]] [--[i]name=EXPR]
|
[===[Usage: find [path] [--type=[dfs]] [--[i]name=EXPR]
|
||||||
@@ -6,10 +6,11 @@ https://raw.githubusercontent.com/OpenPrograms/Wobbo-Programs/master/grep/grep.l
|
|||||||
-- POSIX grep for OpenComputers
|
-- POSIX grep for OpenComputers
|
||||||
-- one difference is that this version uses Lua regex, not POSIX regex.
|
-- one difference is that this version uses Lua regex, not POSIX regex.
|
||||||
|
|
||||||
local fs = require("openos.filesystem")
|
local computer = require("shellex.computer")
|
||||||
local shell = require("openos.shell")
|
local fs = require("shellex.filesystem")
|
||||||
local tty = require("openos.tty")
|
local glob = require('shellex.glob')
|
||||||
local computer = require("openos.computer")
|
local shell = require("shellex.shell")
|
||||||
|
local tty = require("shellex.tty")
|
||||||
|
|
||||||
-- Process the command line arguments
|
-- Process the command line arguments
|
||||||
|
|
||||||
@@ -28,8 +29,14 @@ for more information, run: man grep
|
|||||||
]])
|
]])
|
||||||
end
|
end
|
||||||
|
|
||||||
local PATTERNS = {args[1]}
|
local PATTERNS = { table.remove(args, 1) }
|
||||||
local FILES = {select(2, table.unpack(args))}
|
local FILES = { }
|
||||||
|
for _, arg in pairs(args) do
|
||||||
|
local files = glob.matches(shell.getWorkingDirectory(), arg)
|
||||||
|
for _, v in pairs(files) do
|
||||||
|
table.insert(FILES, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local LABEL_COLOR = 0xb000b0
|
local LABEL_COLOR = 0xb000b0
|
||||||
local LINE_NUM_COLOR = 0x00FF00
|
local LINE_NUM_COLOR = 0x00FF00
|
||||||
@@ -167,7 +174,7 @@ end
|
|||||||
if search_recursively then
|
if search_recursively then
|
||||||
local files = {}
|
local files = {}
|
||||||
for _,arg in ipairs(FILES) do
|
for _,arg in ipairs(FILES) do
|
||||||
if fs.isDirectory(arg) then
|
if fs.isDirectory(shell.resolve(arg)) then
|
||||||
getAllFiles(arg, files)
|
getAllFiles(arg, files)
|
||||||
else
|
else
|
||||||
files[#files+1]=arg
|
files[#files+1]=arg
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
local shell = require("openos.shell")
|
local shell = require("shellex.shell")
|
||||||
local fs = require("openos.filesystem")
|
|
||||||
|
|
||||||
local args, options = shell.parse(...)
|
local args, options = shell.parse(...)
|
||||||
local error_code = 0
|
local error_code = 0
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
local os = _G.os
|
local os = _G.os
|
||||||
|
|
||||||
local shell = require("openos.shell")
|
local shell = require("shellex.shell")
|
||||||
local args = shell.parse(...)
|
local args = shell.parse(...)
|
||||||
local hostname = args[1]
|
local hostname = args[1]
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
local keys = require("openos.keyboard").keys
|
local keys = require("shellex.keyboard").keys
|
||||||
local shell = require("openos.shell")
|
local shell = require("shellex.shell")
|
||||||
local unicode = require("openos.unicode")
|
local unicode = require("shellex.unicode")
|
||||||
local term = require("openos.term") -- using term for negative scroll feature
|
local term = require("shellex.term") -- using term for negative scroll feature
|
||||||
|
|
||||||
local args, ops = shell.parse(...)
|
local args, ops = shell.parse(...)
|
||||||
if #args > 1 then
|
if #args > 1 then
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
local fs = require("openos.filesystem")
|
local fs = require("shellex.filesystem")
|
||||||
local shell = require("openos.shell")
|
local shell = require("shellex.shell")
|
||||||
|
|
||||||
local args = shell.parse(...)
|
local args = shell.parse(...)
|
||||||
if #args == 0 then
|
if #args == 0 then
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
local fs = require("openos.filesystem")
|
local fs = require("shellex.filesystem")
|
||||||
local shell = require("openos.shell")
|
local glob = require('shellex.glob')
|
||||||
local tty = require("openos.tty")
|
local shell = require("shellex.shell")
|
||||||
local unicode = require("openos.unicode")
|
local tty = require("shellex.tty")
|
||||||
local tx = require("openos.transforms")
|
local unicode = require("shellex.unicode")
|
||||||
local text = require("openos.text")
|
local tx = require("shellex.transforms")
|
||||||
|
local text = require("shellex.text")
|
||||||
|
|
||||||
local dirsArg, ops = shell.parse(...)
|
local dirsArg, ops = shell.parse(...)
|
||||||
|
|
||||||
@@ -42,7 +43,6 @@ local function stat(names, index)
|
|||||||
end
|
end
|
||||||
local info = {}
|
local info = {}
|
||||||
info.key = name
|
info.key = name
|
||||||
info._path = name
|
|
||||||
info.path = name:sub(1, 1) == "/" and "" or names.path
|
info.path = name:sub(1, 1) == "/" and "" or names.path
|
||||||
info.full_path = fs.concat(info.path, name)
|
info.full_path = fs.concat(info.path, name)
|
||||||
info.isDir = fs.isDirectory(info.full_path)
|
info.isDir = fs.isDirectory(info.full_path)
|
||||||
@@ -248,7 +248,6 @@ local function display(names)
|
|||||||
local info = stat(names, index)
|
local info = stat(names, index)
|
||||||
local file_type = info.isLink and 'l' or info.isDir and 'd' or 'f'
|
local file_type = info.isLink and 'l' or info.isDir and 'd' or 'f'
|
||||||
local link_target = info.isLink and string.format(" -> %s", info.link:gsub("/+$", "") .. (info.isDir and "/" or "")) or ""
|
local link_target = info.isLink and string.format(" -> %s", info.link:gsub("/+$", "") .. (info.isDir and "/" or "")) or ""
|
||||||
_G._p = info
|
|
||||||
local write_mode = info.fs.isReadOnly() and '-' or 'w'
|
local write_mode = info.fs.isReadOnly() and '-' or 'w'
|
||||||
local size = formatSize(info.size)
|
local size = formatSize(info.size)
|
||||||
local format = "%s-r%s %+"..tostring(max_size_width)..'s '
|
local format = "%s-r%s %+"..tostring(max_size_width)..'s '
|
||||||
@@ -345,6 +344,7 @@ local function displayDirList(dirs)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
--[[
|
||||||
local dir_set, file_set = {}, {path=shell.getWorkingDirectory()}
|
local dir_set, file_set = {}, {path=shell.getWorkingDirectory()}
|
||||||
for _,dir in ipairs(dirsArg) do
|
for _,dir in ipairs(dirsArg) do
|
||||||
local path = shell.resolve(dir)
|
local path = shell.resolve(dir)
|
||||||
@@ -360,6 +360,23 @@ for _,dir in ipairs(dirsArg) do
|
|||||||
table.insert(file_set, dir)
|
table.insert(file_set, dir)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
]]
|
||||||
|
local dir_set, file_set = {}, {path=shell.getWorkingDirectory()}
|
||||||
|
for _,dir in ipairs(dirsArg) do
|
||||||
|
local path = shell.resolve(dir)
|
||||||
|
if fs.isDirectory(path) then
|
||||||
|
table.insert(dir_set, dir)
|
||||||
|
else
|
||||||
|
local files = glob.matches(shell.getWorkingDirectory(), dir)
|
||||||
|
for _, v in pairs(files) do
|
||||||
|
table.insert(file_set, v)
|
||||||
|
end
|
||||||
|
if #files == 0 then
|
||||||
|
local access_msg = "cannot access " .. tostring(dir) .. ": "
|
||||||
|
perr(access_msg .. "No such file or directory")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
io.output():setvbuf("line")
|
io.output():setvbuf("line")
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
local shell = require("openos.shell")
|
local shell = require("shellex.shell")
|
||||||
local transfer = require("openos.transfer")
|
local transfer = require("shellex.transfer")
|
||||||
|
|
||||||
local args, options = shell.parse(...)
|
local args, options = shell.parse(...)
|
||||||
options.h = options.h or options.help
|
options.h = options.h or options.help
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
local fs = require("openos.filesystem")
|
local fs = require("shellex.filesystem")
|
||||||
local shell = require("openos.shell")
|
local glob = require('shellex.glob')
|
||||||
|
local shell = require("shellex.shell")
|
||||||
|
|
||||||
local function usage()
|
local function usage()
|
||||||
print("Usage: rm [options] <filename1> [<filename2> [...]]"..[[
|
print("Usage: rm [options] <filename1> [<filename2> [...]]"..[[
|
||||||
@@ -40,14 +41,14 @@ local function pout(...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local metas = {}
|
local metas = {}
|
||||||
|
local remove
|
||||||
|
|
||||||
-- promptLevel 3 done before fs.exists
|
-- promptLevel 3 done before fs.exists
|
||||||
-- promptLevel 1 asks for each, displaying fs.exists on hit as it visits
|
-- promptLevel 1 asks for each, displaying fs.exists on hit as it visits
|
||||||
|
|
||||||
local function _path(m) return shell.resolve(m.rel) end
|
local function _path(m) return shell.resolve(m.rel) end
|
||||||
local function _link(m) return fs.isLink(_path(m)) end
|
local function _exists(m) return fs.exists(_path(m)) end
|
||||||
local function _exists(m) return _link(m) or fs.exists(_path(m)) end
|
local function _dir(m) return fs.isDirectory(_path(m)) end
|
||||||
local function _dir(m) return not _link(m) and fs.isDirectory(_path(m)) end
|
|
||||||
local function _readonly(m) return not _exists(m) or fs.get(_path(m)).isReadOnly() end
|
local function _readonly(m) return not _exists(m) or fs.get(_path(m)).isReadOnly() end
|
||||||
local function _empty(m) return _exists(m) and _dir(m) and (fs.list(_path(m))==nil) end
|
local function _empty(m) return _exists(m) and _dir(m) and (fs.list(_path(m))==nil) end
|
||||||
|
|
||||||
@@ -94,7 +95,7 @@ local function remove_all(parent)
|
|||||||
return all_ok
|
return all_ok
|
||||||
end
|
end
|
||||||
|
|
||||||
local function remove(meta)
|
remove = function(meta)
|
||||||
if not remove_all(meta) then
|
if not remove_all(meta) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@@ -140,7 +141,10 @@ local function remove(meta)
|
|||||||
end
|
end
|
||||||
|
|
||||||
for _,arg in ipairs(args) do
|
for _,arg in ipairs(args) do
|
||||||
metas[#metas+1] = createMeta(arg, arg)
|
local files = glob.matches(shell.getWorkingDirectory(), arg)
|
||||||
|
for _, v in pairs(files) do
|
||||||
|
metas[#metas+1] = createMeta(v, v)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if promptLevel == 3 and #metas > 3 then
|
if promptLevel == 3 and #metas > 3 then
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
local shell = require("openos.shell")
|
local shell = require("shellex.shell")
|
||||||
local fs = require("openos.filesystem")
|
local fs = require("shellex.filesystem")
|
||||||
local text = require("openos.text")
|
local text = require("shellex.text")
|
||||||
|
|
||||||
local args, options = shell.parse(...)
|
local args, options = shell.parse(...)
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
local computer = require('openos.computer')
|
local computer = require('shellex.computer')
|
||||||
local sh = require('openos.sh')
|
local sh = require('shellex.sh')
|
||||||
|
|
||||||
local real_before, cpu_before = computer.uptime(), os.clock()
|
local real_before, cpu_before = computer.uptime(), os.clock()
|
||||||
local cmd_result = 0
|
local cmd_result = 0
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
--[[Lua implementation of the UN*X touch command--]]
|
--[[Lua implementation of the UN*X touch command--]]
|
||||||
local shell = require("openos.shell")
|
local shell = require("shellex.shell")
|
||||||
local fs = require("openos.filesystem")
|
local fs = require("shellex.filesystem")
|
||||||
|
|
||||||
local args, options = shell.parse(...)
|
local args, options = shell.parse(...)
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
local shell = require("openos.shell")
|
local shell = require("shellex.shell")
|
||||||
|
|
||||||
local args = shell.parse(...)
|
local args = shell.parse(...)
|
||||||
if #args == 0 then
|
if #args == 0 then
|
||||||
Reference in New Issue
Block a user