@@ -0,0 +1,17 @@
|
||||
async function run(ctx, argv) {
|
||||
const parts = argv.slice(1).filter((a) => a !== '--')
|
||||
if (!parts.length) {
|
||||
ctx.console.error('basename: missing operand')
|
||||
return
|
||||
}
|
||||
const path = parts[0]
|
||||
const suffix = parts[1] || ''
|
||||
let base = path.replace(/\/+$/, '')
|
||||
const slash = base.lastIndexOf('/')
|
||||
base = slash === -1 ? base : base.slice(slash + 1)
|
||||
if (!base) base = path
|
||||
if (suffix && base.endsWith(suffix) && base.length > suffix.length) {
|
||||
base = base.slice(0, -suffix.length)
|
||||
}
|
||||
ctx.console.log(base)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
async function run(ctx, argv) {
|
||||
const vfs = ctx.vfs
|
||||
const files = argv.slice(1)
|
||||
if (!files.length) {
|
||||
const s = bareStdin(ctx)
|
||||
ctx.console.log(s)
|
||||
return
|
||||
}
|
||||
for (const f of files) {
|
||||
const buf = await vfs.readFile(f)
|
||||
if (!buf) {
|
||||
ctx.console.error('cat: ' + f + ': No such file or directory')
|
||||
continue
|
||||
}
|
||||
ctx.console.log(ctx.b4a.toString(buf))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
async function run(ctx, argv) {
|
||||
const parts = argv.slice(1).filter((a) => a !== '--')
|
||||
if (!parts.length) {
|
||||
ctx.console.error('dirname: missing operand')
|
||||
return
|
||||
}
|
||||
for (const path of parts) {
|
||||
const cleaned = path.replace(/\/+$/, '') || '/'
|
||||
const i = cleaned.lastIndexOf('/')
|
||||
const out =
|
||||
i <= 0 ? (cleaned[0] === '/' ? '/' : '.') : cleaned.slice(0, i) || '/'
|
||||
ctx.console.log(out)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
async function run(ctx, argv) {
|
||||
const parts = argv.slice(1)
|
||||
let n = false
|
||||
if (parts[0] === '-n') {
|
||||
n = true
|
||||
parts.shift()
|
||||
}
|
||||
const s = parts.join(' ')
|
||||
const w = globalThis.process?.stdout?.write
|
||||
if (typeof w === 'function') {
|
||||
w.call(globalThis.process.stdout, s + (n ? '' : '\n'))
|
||||
} else {
|
||||
ctx.console.log(n ? s : s)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
async function run(ctx, argv) {
|
||||
const vfs = ctx.vfs
|
||||
let n = 10
|
||||
let start = 1
|
||||
if (argv[1] === '-n' && argv[2]) {
|
||||
n = parseInt(argv[2], 10) || 10
|
||||
start = 3
|
||||
} else if (argv[1] && /^-\d+$/.test(argv[1])) {
|
||||
n = parseInt(argv[1].slice(1), 10) || 10
|
||||
start = 2
|
||||
}
|
||||
const files = argv.slice(start).filter((a) => a !== '--')
|
||||
const take = (s) => {
|
||||
const lines = s.split('\n')
|
||||
const out = lines.slice(0, n).join('\n')
|
||||
ctx.console.log(
|
||||
out + (out && !out.endsWith('\n') && lines.length > n ? '\n' : '')
|
||||
)
|
||||
}
|
||||
if (!files.length) {
|
||||
take(bareStdin(ctx))
|
||||
return
|
||||
}
|
||||
for (const f of files) {
|
||||
const buf = await vfs.readFile(f)
|
||||
if (!buf) {
|
||||
ctx.console.error('head: ' + f + ': No such file')
|
||||
continue
|
||||
}
|
||||
if (files.length > 1) ctx.console.log('==> ' + f + ' <==')
|
||||
take(ctx.b4a.toString(buf))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
async function run(ctx, argv) {
|
||||
ctx.console.log(
|
||||
'Bare OS userland — builtins: cd, export, exit | /bin: ls pwd cat echo test basename dirname wc head tail uname pathchk help'
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
async function run(ctx, argv) {
|
||||
const vfs = ctx.vfs
|
||||
let showAll = false
|
||||
let longFmt = false
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '--') {
|
||||
paths.push(...argv.slice(i + 1))
|
||||
break
|
||||
}
|
||||
if (a.startsWith('-') && a.length > 1) {
|
||||
for (let j = 1; j < a.length; j++) {
|
||||
const c = a[j]
|
||||
if (c === 'a') showAll = true
|
||||
else if (c === 'l') longFmt = true
|
||||
else if (c === '1') longFmt = false
|
||||
}
|
||||
continue
|
||||
}
|
||||
paths.push(a)
|
||||
}
|
||||
const targets = paths.length ? paths : ['.']
|
||||
|
||||
for (const t of targets) {
|
||||
if (targets.length > 1) ctx.console.log(t + ':')
|
||||
let names
|
||||
try {
|
||||
names = await vfs.readdir(t)
|
||||
} catch (e) {
|
||||
ctx.console.error('ls: cannot access ' + t + ': ' + (e.message || e))
|
||||
continue
|
||||
}
|
||||
if (!showAll) names = names.filter((n) => n !== '.' && n !== '..')
|
||||
if (!longFmt) {
|
||||
ctx.console.log(names.join(' '))
|
||||
} else {
|
||||
for (const n of names) {
|
||||
const sub = t === '.' || t === './' ? n : t.replace(/\/$/, '') + '/' + n
|
||||
const st = await vfs.stat(sub)
|
||||
const tag = st ? (st.type === 'directory' ? 'd' : '-') : '?'
|
||||
const sz = st && st.size != null ? String(st.size) : '0'
|
||||
ctx.console.log(tag + 'rwxr-xr-x 1 user user ' + sz + ' ' + n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
async function run(ctx, argv) {
|
||||
const paths = argv.slice(1).filter((a) => !a.startsWith('-'))
|
||||
if (!paths.length) {
|
||||
ctx.console.error('pathchk: missing operand')
|
||||
return
|
||||
}
|
||||
for (const p of paths) {
|
||||
if (!p.length) {
|
||||
ctx.console.error('pathchk: empty path name')
|
||||
continue
|
||||
}
|
||||
if (p.length > 4096) {
|
||||
ctx.console.error('pathchk: path too long')
|
||||
continue
|
||||
}
|
||||
if (p.includes('\0')) {
|
||||
ctx.console.error('pathchk: NUL in path')
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
async function run(ctx, argv) {
|
||||
ctx.console.log(ctx.vfs.getcwd())
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
async function run(ctx, argv) {
|
||||
const vfs = ctx.vfs
|
||||
let n = 10
|
||||
let start = 1
|
||||
if (argv[1] === '-n' && argv[2]) {
|
||||
n = parseInt(argv[2], 10) || 10
|
||||
start = 3
|
||||
}
|
||||
const files = argv.slice(start).filter((a) => a !== '--')
|
||||
const take = (s) => {
|
||||
let lines = s.split('\n')
|
||||
if (s.endsWith('\n') && lines[lines.length - 1] === '') lines.pop()
|
||||
const slice = lines.length <= n ? lines : lines.slice(-n)
|
||||
ctx.console.log(slice.join('\n'))
|
||||
}
|
||||
if (!files.length) {
|
||||
take(bareStdin(ctx))
|
||||
return
|
||||
}
|
||||
for (const f of files) {
|
||||
const buf = await vfs.readFile(f)
|
||||
if (!buf) {
|
||||
ctx.console.error('tail: ' + f + ': No such file')
|
||||
continue
|
||||
}
|
||||
if (files.length > 1) ctx.console.log('==> ' + f + ' <==')
|
||||
take(ctx.b4a.toString(buf))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
async function evalTest(ctx, args) {
|
||||
if (!args.length) return false
|
||||
if (args[0] === '!') {
|
||||
const inner = await evalTest(ctx, args.slice(1))
|
||||
return !inner
|
||||
}
|
||||
if (args.length === 3) {
|
||||
const [a, op, b] = args
|
||||
if (op === '=') return a === b
|
||||
if (op === '!=') return a !== b
|
||||
return false
|
||||
}
|
||||
if (args.length === 2) {
|
||||
const op = args[0]
|
||||
const p = args[1]
|
||||
const st = await ctx.vfs.stat(p)
|
||||
if (op === '-e' || op === '-a') return st != null
|
||||
if (op === '-f') return st != null && st.type === 'file'
|
||||
if (op === '-d') return st != null && st.type === 'directory'
|
||||
if (op === '-z') return p.length === 0
|
||||
if (op === '-n') return p.length > 0
|
||||
return false
|
||||
}
|
||||
if (args.length === 1) return args[0] !== ''
|
||||
return false
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
ctx.exitCode = (await evalTest(ctx, argv.slice(1))) ? 0 : 1
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
async function run(ctx, argv) {
|
||||
const flagArgs = argv.slice(1).filter((a) => a.startsWith('-') && a !== '--')
|
||||
const all = argv.includes('-a')
|
||||
const noFlag = flagArgs.length === 0
|
||||
const wantS = all || argv.includes('-s') || noFlag
|
||||
const wantN = all || argv.includes('-n')
|
||||
const wantR = all || argv.includes('-r')
|
||||
const wantM = all || argv.includes('-m')
|
||||
const wantV = all || argv.includes('-v')
|
||||
|
||||
let name = 'BareOS'
|
||||
let version = '0.1'
|
||||
const buf = await ctx.vfs.readFile('/etc/os-release')
|
||||
if (buf) {
|
||||
const t = ctx.b4a.toString(buf)
|
||||
for (const line of t.split('\n')) {
|
||||
const id = line.match(/^NAME=(.*)$/)
|
||||
if (id) name = id[1].replace(/^"|"$/g, '')
|
||||
const ver = line.match(/^VERSION=(.*)$/)
|
||||
if (ver) version = ver[1].replace(/^"|"$/g, '')
|
||||
}
|
||||
}
|
||||
|
||||
const parts = []
|
||||
if (wantS) parts.push(name)
|
||||
if (wantN) parts.push('bare-os')
|
||||
if (wantR) parts.push(version)
|
||||
if (wantV) parts.push('bare-userland')
|
||||
if (wantM) parts.push('unknown')
|
||||
|
||||
ctx.console.log(parts.join(' '))
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
function count(s) {
|
||||
const lines = (s.match(/\n/g) || []).length
|
||||
const words = s.trim() ? s.trim().split(/\s+/).length : 0
|
||||
const bytes = new TextEncoder().encode(s).length
|
||||
return { lines, words, bytes }
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
const vfs = ctx.vfs
|
||||
const files = argv.slice(1).filter((a) => !a.startsWith('-'))
|
||||
if (!files.length) {
|
||||
const s = bareStdin(ctx)
|
||||
const c = count(s)
|
||||
ctx.console.log(' ' + c.lines + ' ' + c.words + ' ' + c.bytes)
|
||||
return
|
||||
}
|
||||
let tLines = 0
|
||||
let tWords = 0
|
||||
let tBytes = 0
|
||||
for (const f of files) {
|
||||
const buf = await vfs.readFile(f)
|
||||
if (!buf) {
|
||||
ctx.console.error('wc: ' + f + ': No such file')
|
||||
continue
|
||||
}
|
||||
const s = ctx.b4a.toString(buf)
|
||||
const c = count(s)
|
||||
tLines += c.lines
|
||||
tWords += c.words
|
||||
tBytes += c.bytes
|
||||
ctx.console.log(' ' + c.lines + ' ' + c.words + ' ' + c.bytes + ' ' + f)
|
||||
}
|
||||
if (files.length > 1) {
|
||||
ctx.console.log(' ' + tLines + ' ' + tWords + ' ' + tBytes + ' total')
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user