#lang scribble/manual @(require (for-label racket/base (only-in rash-coreutils coreutils-pwd coreutils-ls coreutils-mkdir coreutils-rmdir coreutils-rm coreutils-cp coreutils-mv coreutils-cat coreutils-touch coreutils-echo coreutils-which coreutils-head coreutils-tail coreutils-wc coreutils-sort coreutils-uniq coreutils-cut coreutils-tee coreutils-tr coreutils-basename coreutils-dirname coreutils-realpath coreutils-readlink coreutils-stat coreutils-du coreutils-df coreutils-mktemp coreutils-printenv coreutils-env coreutils-date raco coreutils-raco))) @title{rash-coreutils} @author["Hans Dijkema / hans@dijkewijk.nl"] @defmodule[rash-coreutils] @bold{rash-coreutils} provides platform-independent Unix-style shell commands for Rash. The commands are implemented in Racket, so common shell utilities do not depend on @tt{cmd.exe}, PowerShell, or Unix executables being installed. Rash remains responsible for shell syntax such as pipelines, globbing, tilde expansion, variable expansion, and redirection. @bold{rash-coreutils} supplies the commands themselves plus Racket-specific additions such as regular-expression path selectors. @section{Commands} The package provides @tt{pwd}, @tt{ls}, @tt{mkdir}, @tt{rmdir}, @tt{rm}, @tt{cp}, @tt{mv}, @tt{cat}, @tt{touch}, @tt{echo}, @tt{which}, @tt{head}, @tt{tail}, @tt{wc}, @tt{sort}, @tt{uniq}, @tt{cut}, @tt{tee}, @tt{tr}, @tt{basename}, @tt{dirname}, @tt{realpath}, @tt{readlink}, @tt{stat}, @tt{du}, @tt{df}, @tt{mktemp}, @tt{printenv}, @tt{env}, @tt{date}, @tt{raco}, and @tt{help}. The option set is deliberately smaller than GNU coreutils. Unsupported options raise an error instead of silently approximating another command's behavior. @section{Racket procedures} Each shell command has an explicitly named Racket procedure. All procedures write to the normal current ports so Rash pipeline and redirection semantics continue to work. @index["rash-coreutils-pwd"] @defproc[(coreutils-pwd) void?]{Writes the current directory.} @index["rash-coreutils-ls"] @defproc[(coreutils-ls [arg any/c] ...) void?]{Lists paths. Supports @tt{-a}, @tt{-l}, and their long forms.} @index["rash-coreutils-mkdir"] @defproc[(coreutils-mkdir [arg any/c] ...) void?]{Creates directories. Supports @tt{-p}.} @index["rash-coreutils-rmdir"] @defproc[(coreutils-rmdir [arg any/c] ...) void?]{Removes empty directories.} @index["rash-coreutils-rm"] @defproc[(coreutils-rm [arg any/c] ...) void?]{Removes paths. Supports recursive and force options.} @index["rash-coreutils-cp"] @defproc[(coreutils-cp [arg any/c] ...) void?]{Copies a source to a destination. Directory copies require @tt{-r}.} @index["rash-coreutils-mv"] @defproc[(coreutils-mv [source any/c] [destination any/c]) void?]{Moves or renames a path.} @index["rash-coreutils-cat"] @defproc[(coreutils-cat [arg any/c] ...) void?]{Copies files, or standard input, to standard output.} @index["rash-coreutils-touch"] @defproc[(coreutils-touch [arg any/c] ...) void?]{Updates modification times or creates empty files.} @index["rash-coreutils-echo"] @defproc[(coreutils-echo [arg any/c] ...) void?]{Writes arguments separated by spaces.} @index["rash-coreutils-which"] @defproc[(coreutils-which [arg any/c] ...) void?]{Finds executables using Racket's executable search.} @index["rash-coreutils-head"] @defproc[(coreutils-head [arg any/c] ...) void?]{Writes the first lines of input. Supports @tt{-n}.} @index["rash-coreutils-tail"] @defproc[(coreutils-tail [arg any/c] ...) void?]{Writes the last lines of input. Supports @tt{-n}.} @index["rash-coreutils-wc"] @defproc[(coreutils-wc [arg any/c] ...) void?]{Counts lines, words, and bytes. Supports @tt{-l}, @tt{-w}, and @tt{-c}.} @index["rash-coreutils-sort"] @defproc[(coreutils-sort [arg any/c] ...) void?]{Sorts lines. Supports @tt{-r} and @tt{-n}.} @index["rash-coreutils-uniq"] @defproc[(coreutils-uniq [arg any/c] ...) void?]{Collapses adjacent duplicate lines. Supports @tt{-c}.} @index["rash-coreutils-cut"] @defproc[(coreutils-cut [arg any/c] ...) void?]{Selects one delimited field with @tt{-d} and @tt{-f}.} @index["rash-coreutils-tee"] @defproc[(coreutils-tee [arg any/c] ...) void?]{Copies standard input to standard output and files. Supports @tt{-a}.} @index["rash-coreutils-tr"] @defproc[(coreutils-tr [arg any/c] ...) void?]{Translates characters from standard input. Character ranges such as @tt{a-z}, @tt{A-Z}, and @tt{0-9} are expanded. @tt{-d} deletes characters and @tt{-s} squeezes repeated characters.} @index["rash-coreutils-basename"] @defproc[(coreutils-basename [path any/c]) void?]{Writes the final path component.} @index["rash-coreutils-dirname"] @defproc[(coreutils-dirname [path any/c]) void?]{Writes the directory portion of a path.} @index["rash-coreutils-realpath"] @defproc[(coreutils-realpath [path any/c]) void?]{Writes a complete simplified path.} @index["rash-coreutils-readlink"] @defproc[(coreutils-readlink [path any/c]) void?]{Resolves a symbolic link.} @index["rash-coreutils-stat"] @defproc[(coreutils-stat [path any/c] ...) void?]{Writes basic portable path metadata.} @index["rash-coreutils-du"] @defproc[(coreutils-du [arg any/c] ...) void?]{Calculates recursive file size. Supports @tt{-h}.} @index["rash-coreutils-df"] @defproc[(coreutils-df) void?]{Lists filesystem roots. Racket has no portable API for total and free filesystem capacity, so this initial implementation deliberately does not invent platform-specific subprocess fallbacks.} @index["rash-coreutils-mktemp"] @defproc[(coreutils-mktemp [arg any/c] ...) void?]{Creates a temporary file, or a directory with @tt{-d}, and writes its path.} @index["rash-coreutils-printenv"] @defproc[(coreutils-printenv [name any/c] ...) void?]{Writes environment variables.} @index["rash-coreutils-env"] @defproc[(coreutils-env [arg any/c] ...) void?]{Creates a copied environment, applies leading @tt{NAME=value} assignments, and either writes that environment or runs the remaining command in it. Racket values are converted to environment strings.} The Rash form can mix shell-style assignment names with Racket expressions: @verbatim{ (define x 42) env ANSWER=(values x) printenv ANSWER } A parenthesized expression in Rash line mode is ordinary Racket code. Therefore the value after an empty @tt{NAME=} token can be a number, symbol, path, string, or another printable Racket value. @index["rash-coreutils-date"] @defproc[(coreutils-date [arg any/c] ...) void?]{Writes the current date and time using Gregor. Supports @tt{-u}/@tt{--utc}, @tt{-I}/@tt{--iso}, @tt{--tz ZONE}, and @tt{--format CLDR-PATTERN}. The format pattern follows Gregor's CLDR syntax rather than pretending to implement every GNU @tt{date} format escape.} @verbatim{ date date --iso date --utc --iso date --tz Europe/Amsterdam --format "yyyy-MM-dd HH:mm:ss" } @index["rash-coreutils-raco"] @defproc[(raco [arg any/c] ...) void?]{Runs @tt{raco} from the current Racket installation. The executable is resolved from the active Racket installation before PATH is considered, so it also works on Windows when @tt{raco.exe} is not on PATH. Arguments may be strings, symbols, paths, numbers, or nested lists. With no arguments, the underlying @tt{raco} program is invoked without a subcommand.} @defproc[(coreutils-raco [arg any/c] ...) void?]{Explicit implementation name for @racket[raco].} @verbatim{ raco setup rash-coreutils raco pkg show } The same @racket[raco] binding is a normal Racket procedure, so expression-mode code can use @racket[(raco '(setup rash-coreutils))]. The explicit implementation name @racket[coreutils-raco] is also exported. @section{Path selection} Shell-style argument expansion remains Rash's responsibility. The aliases expand back into Rash's @tt{=unix-pipe=} operator, preserving Rash globbing, tilde expansion, and @tt{$} expansion. @verbatim{ ls *.rkt ls -l info* cat info* } Regular-expression values are an additional @bold{rash-coreutils} selector. A @racket[#rx""] or @racket[#px""] value is matched against entry names in the current directory. @verbatim{ ls #px"^info[0-9]+[.]rkt$" } @section{Windows paths} On Windows, commands that write path names use forward slashes in their textual output. Rash treats backslashes as escape characters in line mode, so a printed path such as @tt{C:/Users/name/AppData/Local/Temp/file} can be copied directly into another Rash command. Racket path values themselves remain native and can be passed directly to a command through a Racket expression. @section{Help} @tt{help} uses Racket's documentation search through @tt{raco docs}. Registered commands use package-specific index terms such as @tt{rash-coreutils-ls}. @verbatim{ help help ls ls --help help directory-list } @section{Capturing and redirecting output} Commands use normal ports. Rash can therefore capture or redirect them without special support in this package. @verbatim{ (define git-path { which git |> read-line }) ls &> listing.txt cat info.rkt &>! copy.rkt } @section{Compatibility scope} The command names and common options follow Unix conventions, but this package does not claim complete GNU coreutils compatibility. Platform-independent behavior, predictable Rash scripting, and useful integration with Racket values are the primary goals.