. back to top ↑
Read and execute commands from file (alias for source).
No detailed man page yet — see the one-line summary above.
All 245 commands built into cshw. Type to filter the list; press Enter to jump to the first match.
| Command | Description |
|---|---|
. | Read and execute commands from file (alias for source). |
@ | arithmetic assignment (csh-style) |
[ | Evaluate a conditional expression (test, requires a closing ]). |
about | show the CSHW About dialog |
addcontrol | add a child control to a script-owned window |
adopt | bring an already-running process under job control |
alias | create command aliases |
array | create or manipulate an indexed array variable |
attrib | display or change file attributes |
awk | pattern-scanning and text-processing language |
barrier | rendezvous barrier for N participants |
base | print a number in another radix |
base64 | encode or decode base64 data |
basename | strip directory and suffix from a path |
bc | arbitrary-precision calculator language |
bg | move job to background |
bindevent | bind a script proc as a window event handler |
bugreport | compose and send a bug report to bugs@tropibyte.com |
cancel | remove jobs from a print queue (System V spelling of lprm) |
cat | concatenate file(s) (or stdin) to standard output |
cd | change the current working directory |
chancreate | create a message-passing channel (shorthand) |
channel | message-passing channel between coroutines |
chdir | change the current working directory (alias for cd) |
checkmail | check $mail now for new messages |
chmod | change file permissions |
chown | change file owner |
clip | copy to clipboard |
cls | clear the console screen |
cmdliblist | list loaded command libraries |
cocancel | cancel a running coroutine |
cocas | atomic compare-and-swap on a thread-safe variable |
coclean | remove completed coroutines from tracking |
codecr | atomically decrement a thread-safe variable |
coget | read a thread-safe atomic variable |
coincr | atomically increment a thread-safe variable |
colist | list coroutines and their status |
complete | define tab completion rules |
copy | copy files |
coresult | get the result of a completed coroutine |
coresume | resume a suspended coroutine |
corunproc | start a procedure as a concurrent coroutine |
coset | set a thread-safe atomic variable |
cosuspend | suspend a running coroutine |
cowait | wait for coroutine(s) to complete |
cp | copy files (alias for copy) |
createwindow | create a script-owned window on the UI thread |
crond | cron daemon control |
crontab | manage scheduled cron jobs |
cut | remove sections from each line |
date | display or format the current date and time |
dc | reverse-Polish arbitrary-precision calculator |
declare | declare a variable with optional type / scope flags |
del | delete files |
df | display disk free space |
diff | compare files line by line |
dir | display directory contents |
dirname | strip the last component from a path |
dirs | display directory stack |
disown | release a job without stopping the process |
dllimport | load DLL for function calls |
dlllist | list imported DLLs |
dllunload | unload a previously imported DLL |
du | estimate file space usage |
echo | display text or variable values |
enable | Enable or disable a built-in (bash's spelling of shadow). |
endsplash | dismiss the modeless splash dialog |
env | display or modify environment |
eval | concatenate arguments and run the result as a command |
event | manual/auto-reset event signal |
example | Show or run a bundled example script. |
exec | replace shell with command |
exit | exit the shell |
false | return failure (documented with true) |
fetch | transfer data from a URL (HTTP/HTTPS/FTP client) |
fg | move job to foreground |
file | identify file type |
file-rename | rename files with a Perl-style expression |
fileblob | encode a file into a one-line text blob |
find | search for files in a directory tree |
fmt | reflow paragraphs to a width |
fold | wrap long lines to a fixed width |
ftpfetch | FTP file transfer client |
genai | interact with AI language models |
glob | expand filename patterns |
grep | search for patterns in files |
hash | create or manipulate an associative array (hash) variable |
hashstat | display command hash table statistics |
head | output the first part of files |
help | display command help |
hexdump | display file contents in hexadecimal |
history | display command history |
hostname | display the system hostname |
install | install cshw onto the system |
isWindows | test whether the shell is running on Windows |
jobs | display status of background jobs |
kad | kill process and secure-delete its executable (alias for killanddel) |
kill | terminate processes |
killanddel | kill processes and securely delete executables |
lc | count lines in files |
library | load CSHW script as procedure library |
limit | display resource limits |
linecount | count lines in files (alias for lc) |
local | declare a variable in the current procedure's scope |
log | tee stdout and stderr to a file while still showing them |
login | log in as a different user |
logout | end a login shell |
lp | send a file to a printer, or render it to a file |
lpadmin | Printer administration. |
lpc | control a print queue |
lpq | list the jobs in a print queue |
lpr | send a file to a printer (BSD spelling of lp) |
lprm | remove jobs from a print queue |
lpstat | show printers and what they will accept |
ls | list directory contents (native, not a shell-out) |
man | display manual pages |
md | make a directory (alias for mkdir) |
md5sum | compute MD5 message digest |
messagebox | show a Win32 message box |
mkdir | create directories |
mklink | create symbolic and hard links |
more | display text one screen at a time |
msgbox | display a message box |
mutex | mutual-exclusion lock |
mv | move or rename files and directories |
nice | run command with modified priority |
nl | number the lines of a file |
nohup | run command immune to hangups |
nop | no operation (alias for true) |
notify | enable job completion notifications |
onintr | set interrupt handler |
password | read a password from the console (no echo) |
passworddlg | prompt for a password using a modal dialog |
pathmap | map Unix-style paths to Windows destinations |
peinfo | display PE file information |
popd | pop directory from stack and change to it |
postmessage | post a Win32 message to a window's queue (async) |
pr | paginate text for printing |
prename | rename files with a Perl-style expression |
printenv | print environment variables |
printf | format and print arguments |
processlist | list running processes |
progressdlg | show and drive a modeless progress dialog |
prompt | set or display command prompt |
ps | Lists all the processes running on the system (alias for processlist). |
pushd | push directory onto stack and change to it |
pwd | print working directory |
quicsrv | launch and supervise quicsrv QUIC/UDP (HTTP/3) server worker processes |
rcl | register command library (load plugin DLL) |
rd | remove a directory (alias for rmdir) |
readfile | read a file's contents into a shell variable |
readonly | make a variable read-only |
realpath | print the absolute, canonical form of a path |
registercmdlib | register command library (load plugin DLL) |
registry | in-shell Windows Registry operations |
rehash | rebuild command lookup hash table |
rename | rename a file, or substitute in many file names |
repeat | run a command a given number of times |
retproc | return from the current procedure with a value |
retshell | exit a sourced script without killing the shell |
rev | reverse lines character by character |
rm | remove files |
rmdir | remove directories |
rundllproc | call an exported function from a DLL |
say | print a system value (time, date, hostname, etc.) and capture it |
sed | stream editor for filtering and transforming text |
semaphore | counting semaphore |
semcreate | create a counting semaphore (shorthand) |
sendmessage | send a Win32 message to a window (synchronous) |
seq | print sequence of numbers |
service | manage Windows services |
set | set or display shell variables |
setenv | set environment variable |
sha1sum | compute SHA-1 message digest |
sha256sum | compute SHA-256 message digest |
sha512sum | compute SHA-512 message digest |
shadow | hide a built-in so a program of the same name runs instead |
share | assign a variable in the global namespace (write-through) |
shasum | compute or verify a SHA hash with a selectable algorithm |
shift | shift positional parameters |
shutdown | shutdown, restart, or log off the system |
sleep | pause the current thread of execution for a duration |
socket | low-level socket operations |
sort | sort lines of text |
source | execute commands from a file in the current shell |
spawn | start another cshw instance in a new console window |
splash | show a modeless splash dialog during a long-running step |
splitpath | print the components of a path, one per line |
start | start a program or open a file |
stat | display file status information |
stop | suspend a running job |
strings | extract printable strings from files |
sudo | run command as Administrator |
suspend | manage system power state from the shell |
sync | list and destroy synchronization objects |
tac | concatenate and print files in reverse line order |
tail | output the last part of files |
tar | archive files |
tc | time how long a command takes to run |
tcpclient | one-shot TCP client |
tcpserver | start a TCP server |
tee | read from stdin and write to stdout and files |
test | evaluate a conditional expression |
testsplash | [INTERNAL] exercise the splash dialog in a chosen mode |
time | measure command execution time |
timeout | run command with time limit |
title | set or display the console window title |
tokenize | display parsed tokens from input |
touch | change file timestamps or create empty files |
tr | translate or delete characters |
tree | display a directory structure graphically |
true | succeed or fail with no side effects |
tsrvd | launch and supervise tsrvd server worker processes |
type | display file contents |
umask | set file creation mode mask |
unalias | remove command aliases |
uname | print system information |
unbindevent | remove a window event binding |
uncomplete | remove tab completion rules |
unfileblob | decode a fileblob back into a file |
unhash | remove command from hash table |
uniq | report or filter out repeated lines |
unlimit | report that resource limits cannot be removed |
unregistercmdlib | unregister command library (unload plugin DLL) |
unset | remove shell variables |
unsetenv | remove environment variable |
unshadow | restore a built-in hidden by shadow |
unzip | extract or list a .zip archive |
uptime | show how long system has been running |
urcl | unregister command library (unload plugin DLL) |
vartype | display variable type |
ver | display shell version (alias for version) |
version | display shell version |
vol | display a volume's label and serial number |
wait | Wait for all running coroutines (alias for `cowait /all`). |
watch | execute command periodically |
wc | word, line, character, and byte count |
where | locate every place a command name resolves |
which | locate a command |
whoami | display current user name |
winapi | call a Win32 API by name with auto-resolution of its DLL |
winver | display Windows version |
writefile | write a shell variable's contents to a file |
xargs | build command lines from standard input and run them |
zip | create a .zip archive (Windows-style) |
. back to top ↑Read and execute commands from file (alias for source).
No detailed man page yet — see the one-line summary above.
@ back to top ↑arithmetic assignment (csh-style)
@ VAR = EXPRESSION
@ VAR <op>= EXPRESSION # += -= *= /= %= &= |= ^= <<= >>=
@ VAR++ | @ VAR--
Evaluates EXPRESSION and assigns the result to the shell variable VAR. csh-style in spirit but with C-style precedence and left associativity, so `2 + 3 * 4` is 14, not 20. Integer operands keep integer results; a float operand or a math primitive promotes the result to floating point. Compound-assign forms (+=, -=, ...) and the ++ / -- forms update VAR in place.
Constants: pi, e, tau.
Operators (high to low precedence):
unary - + ! ~
* / % (modulo is integer; use fmod(a,b) for floats)
+ -
<< >> (integer)
< <= > >=
== !=
& ^ | (integer bitwise)
&& ||
Math primitives:
trig: sin cos tan asin acos atan atan2(y,x)
hyperbolic: sinh cosh tanh
logs/exp: log (= ln) log10 log2 exp
powers: sqrt cbrt pow(b,e) hypot(a,b) root(x,n)
rounding: floor ceil round trunc fmod(a,b)
misc: abs sign min(a,b) max(a,b)
@ count = 0
@ count++
@ result = 5 + 3
@ angle = pi / 4
@ x = sin(angle) * sqrt(2)
@ fourth = root(256, 4) # 4.0 (same as pow(256, 0.25))
@ deg = atan2(1, 1) * 180 / pi
0 Assigned. >0 Parse/evaluation error (e.g. division by zero, bad expression).
[ back to top ↑Evaluate a conditional expression (test, requires a closing ]).
No detailed man page yet — see the one-line summary above.
about back to top ↑show the CSHW About dialog
about [/min | /minimal | /nerdy | /nerd | /lyrical]
Displays a modal About dialog showing the CSHW version and copyright information. The dialog appears on the UI thread, falling back to a self-contained modal pump when CSHW is running in non-interactive mode.
/lyrical (default) Short tagline + credits.
/min Minimal -- title, version, and copyright only.
/minimal Same as /min.
/nerdy Verbose -- build date/time, compiler, architecture,
bundled library versions.
/nerd Same as /nerdy.
about
Show the default (lyrical) variant.
about /nerdy
Show build details for diagnostic / bug-report purposes.
0 Always (the dialog closes silently).
addcontrol back to top ↑add a child control to a script-owned window
addcontrol <type> <parent_hwnd> [<text>]
[/pos:x,y] [/size:w,h] [/id:<n>] [/style:extra]
Creates a standard Win32 child control inside a parent window (typically one made by `createwindow`). Type-aware defaults handle the class name and the common style bits; you only specify position, size, id, and text. The created control is auto-subclassed so `bindevent` against it Just Works.
<type> One of:
button -- BS_PUSHBUTTON | WS_TABSTOP
defbutton -- BS_DEFPUSHBUTTON | WS_TABSTOP
checkbox -- BS_AUTOCHECKBOX | WS_TABSTOP
radio -- BS_AUTORADIOBUTTON | WS_TABSTOP
groupbox -- BS_GROUPBOX
label -- STATIC SS_LEFT
edit -- EDIT ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP
textarea -- EDIT multi-line, vertical scroll
listbox -- LISTBOX LBS_NOTIFY | WS_VSCROLL
combobox -- COMBOBOX CBS_DROPDOWNLIST | WS_VSCROLL
progress -- msctls_progress32
<parent_hwnd>
Parent window HWND (hex or decimal).
<text> Initial text / button label.
/pos:x,y Position relative to parent client area. Default: 0,0.
/size:w,h Control size. Default: 100x24.
/id:<n> Control id (the LOWORD of wParam in WM_COMMAND). Default 0.
/style:extra
Additional WS_* / BS_* / ES_* etc. bits to OR in.
WS_CHILD | WS_VISIBLE are always set automatically.
createwindow "" "Form" /size:300,200
set w = $result
addcontrol label $w "Name:" /pos:10,10 /size:60,20
addcontrol edit $w "" /pos:80,10 /size:200,20 /id:1
addcontrol button $w "&OK" /pos:100,150 /size:80,25 /id:100
proc on_ok
echo "OK clicked"
endproc
bindevent $w command 100 on_ok
0 Success; $result is the new control HWND in hex. 1 Unknown control type, bad args, or UI thread unavailable.
adopt back to top ↑bring an already-running process under job control
adopt PID
Adds a process cshw did not start to this shell's job table, so the ordinary job-control verbs work on it: jobs, stop, bg, fg, kill, wait, and the %n job specifications.
Find the PID with 'ps' (or 'processlist'), then adopt it.
The process keeps running throughout; adopting it changes nothing about the process itself, only what this shell knows about it.
PID Process ID to adopt. Must be a live process.
ps | grep notepad
# notepad.exe 41288
adopt 41288
# [1] 41288 C:\WINDOWS\system32\notepad.exe
adopt 41288
stop %1
Freeze it.
bg %1
Let it run again.
disown %1
Release it from job control, leaving it running.
0 Adopted
1 No such process, already adopted, access denied, or the
process has already exited
Differences from a process cshw launched itself:
- No targeted signal. cshw gives processes it starts their own process group, which is how a graceful 'kill' reaches them directly. An adopted process is not in such a group, so a graceful kill can only try WM_CLOSE. The console-broadcast fallback is deliberately NOT used on adopted processes: it requires detaching cshw from its own console, and a failed reattach leaves the shell with no console at all.
- 'fg' waits for the process to exit, but it was never attached to this console, so "foreground" means only that cshw is blocked until it ends.
- Adopting a process running at higher integrity requires an elevated cshw. Without it, OpenProcess fails and adopt reports access denied rather than half-succeeding.
- If the process cannot be assigned to a job object, adopt still succeeds but says so: stop and bg then act on that process alone rather than on it and its children.
cshw refuses to adopt its own process.
alias back to top ↑create command aliases
alias
alias NAME=COMMAND
alias NAME COMMAND
Creates a shortcut name for a command or displays existing aliases. Aliases allow you to create shorter or more memorable names for frequently used commands or command sequences.
When a command is entered, CSHW first checks if it's an alias before looking for built-in commands or external programs. This allows aliases to override default behavior.
NAME The alias name to create.
COMMAND The command the alias expands to.
alias
Display all defined aliases.
alias ll=dir
Create 'll' as an alias for 'dir'.
alias la="dir /a"
Create 'la' for 'dir /a' (show all including hidden).
alias cls=clear
Make 'clear' work like 'cls'.
alias ..="cd .."
Create '..' to go up one directory.
alias ...="cd ..\.."
Create '...' to go up two directories.
alias h=history
Short alias for history command.
alias g=grep
Short alias for grep command.
alias projects="cd C:\Users\Me\Projects"
Quick navigation alias.
0 Success 1 Invalid alias name 2 Syntax error
Alias Persistence: Aliases are not persisted across shell sessions. To make aliases permanent, add them to your shell startup script. On interactive startup, CSHW loads %USERPROFILE%\.cshrc first; if it is missing, it falls back to %APPDATA%\cshw\cshwrc.
Alias Expansion: Aliases are expanded before command execution. An alias can include switches and arguments.
Resolution order: proc > alias > built-in > PATH
An alias beats a built-in, as it does in tcsh and bash. That is what makes `alias ls 'ls -l'` do anything at all. A procedure beats both.
Recursion: An expansion is re-scanned, so aliases chain:
alias ll "ls -l" alias lla "ll -a" # ll expands too
The exception is what makes the commonest alias in existence terminate: if the FIRST WORD of an expansion is the alias being expanded, it is not expanded again. So
alias ls "ls -l"
becomes `ls -l` exactly once, and that `ls` reaches the built-in rather than looping. A genuine cycle across different names -- `alias a b` with `alias b a` -- is caught by a depth limit and reported as "Alias loop."
Getting past an alias: There is no backslash escape here. tcsh lets you type \ls to bypass an alias for one command; in cshw that does nothing special. Use the full path, or unalias the name. To hide a BUILT-IN so a program of the same name runs instead, that is a different tool: see shadow(1).
array back to top ↑create or manipulate an indexed array variable
array <name>
array <name> <value1> <value2> ... <valueN>
array set <name> <index> <value>
array get <name> <index>
array push <name> <value>
array size <name>
array list <name>
Creates an indexed array variable. With only a name, creates an empty array. With trailing values, initializes the array with those elements.
SUBSCRIPTS ARE 1-BASED, as they are in csh: element 1 is the first. That holds everywhere -- `$name[1]`, `set name[1] = v`, `array set name 1 v`, `array get name 1`, and the indices `array list` prints.
`[0]` IS OUT OF RANGE, as it is in tcsh, on every one of those paths. It was tolerated as `[1]` for a while, as a bridge for an earlier printing of the book which described the arrays as 0-based because the first implementation was. A second numbering scheme is what made the off-by-one hard to see, so the bridge is gone: write 0 and you are told, rather than reading element 1 and never finding out.
`loop`'s counter and $loopindex are 1-based too, so `loop $#a as i` pairs with `$a[$i]` directly and reads every element. `for` and `while` are unchanged and still let you choose your own bounds.
`array set` and `array get` used to take the index as 0-based storage while `$name[n]` was 1-based, so `array set c 2 X` wrote element 3 and `set c[2] = Y` wrote element 2 -- two bases for the same array, with nothing to say which had just been used.
Elements are read with `$name[<i>]` and written with `set name[<i>] = <value>` or `array set`. `array push` appends.
Re-declaring an array with no values keeps its contents, so a script that declares its arrays at the top can be sourced twice. Re-declaring WITH values replaces them.
<name> Array name. Same rules as scalar variable names.
<values> Optional initial elements.
set NAME INDEX VALUE Set element INDEX (1-based).
get NAME INDEX Print element INDEX and set $result to it.
push NAME VALUE Append VALUE as a new last element.
size NAME Print the number of elements.
list NAME Print every element as "[i] = value".
array colors red green blue
echo "first is $colors[1]" # red
echo "count = $#colors" # 3
array set colors 2 GREEN # element 2, not 3
array push colors yellow
array list colors # [1] = red ... [4] = yellow
array empty
set empty[1] = "first"
set empty[2] = "second"
echo "count = $#empty" # 2
# Iteration:
foreach c ($colors)
echo $c
end
0 Array declared / updated / reported.
1 Bad name, an index that is not a number, an unknown
subcommand, or a variable that is not set.
An index that will not parse is an ERROR, not element 1. `array set c oops X` used to overwrite the FIRST element and return 0 -- a typo silently corrupting data and reporting success.
`array list` and `array size` report a variable that is not set rather than printing nothing or 0. `$#name` still expands to 0 for an unset name: an EXPANSION yields a value into a larger expression, a COMMAND performs an action and has a status to say how it went.
Every variable is subscriptable: Subscripting is by WORD and works on any variable, not just ones made with `array` or with parentheses -- csh's only variable is a word list, and a plain string is a one-word list:
set e = one echo $e[1] -> one echo $#e -> 1
So `$name[1]` is safe on a variable you did not build as an array. It used to return the first CHARACTER for a non-array, which made the subscript mean different things depending on a type the script could not see.
For characters rather than words, use the substring form ${var:off:len}, which is 0-indexed. See `man set`.
For string-keyed (associative) arrays, see `hash`. Both styles are distinct: an indexed array uses integer indices in [], a hash uses string keys in {}.
attrib back to top ↑display or change file attributes
attrib FILE
attrib [+|-]ATTR FILE
Displays or modifies file attributes. Windows files have several attributes that control visibility, backup status, and system protection.
FILE File(s) to examine or modify.
Attributes (prefix with + to set, - to clear):
R Read-only - prevents modification
H Hidden - not shown in normal listings
S System - marks as system file
A Archive - file needs backup
/s Process files in subdirectories.
/d Process directories as well as files.
attrib file.txt
Display attributes of file.txt.
attrib +R important.doc
Make file read-only.
attrib -R important.doc
Remove read-only attribute.
attrib +H secret.txt
Hide a file.
attrib -H -S file.txt
Remove hidden and system attributes.
attrib -R /s *.txt
Remove read-only from all .txt files recursively.
attrib +A /s *.*
Mark all files as needing backup.
0 Success 1 File not found 2 Access denied
Attribute Meanings: R (Read-only) - Prevents file modification. Must be cleared before editing or deleting the file. H (Hidden) - File won't appear in normal dir listings. Use 'dir /ah' to show hidden files. S (System) - Marks file as system file. Often combined with Hidden for Windows system files. A (Archive) - Indicates file has changed since last backup. Backup software uses this to detect changes.
Combining Attributes: You can set or clear multiple attributes at once: attrib +R +H file.txt
Protected System Files: Some system files have both +S and +H and may require special handling to modify.
awk back to top ↑pattern-scanning and text-processing language
awk [OPTIONS]... 'PROGRAM' [FILE]...
awk [OPTIONS]... -f SCRIPT-FILE [FILE]...
command | awk [OPTIONS]... 'PROGRAM'
awk reads text from one or more input files (or standard input), splits each line into fields, and runs a program of pattern-action rules against every line. It is the classic Unix tool for column-oriented text processing -- extracting columns, computing sums, reformatting delimited data, and producing reports.
cshw's awk implements a substantial POSIX awk subset, with PCRE2 as the regex engine (so lookahead, lookbehind, and Unicode classes all work) and dual Windows-style and Unix-style switch spellings. Programs run top-to-bottom over each input record: the BEGIN block fires once before input, the END block fires once after, and rule patterns select which records each action applies to.
-F SEP, --field-separator=SEP, /F:SEP
Set the input field separator. SEP can be a single
character, a regex, or the special value " " (default,
which splits on runs of whitespace AND trims leading/
trailing whitespace from each record).
-f FILE, --file=FILE, /f:FILE
Read the awk program from FILE instead of from the
command line. Multiple -f options are accepted; their
contents are concatenated.
-v VAR=VALUE, --assign VAR=VALUE, /v:VAR=VALUE
Predefine an awk variable before execution. Repeatable.
The assignment happens after BEGIN's first variable
lookup, so -v sets variables visible to BEGIN.
Switch aliases:
cshw accepts both Unix-style (-x / --xxx) and Windows-style (/x:val)
spellings everywhere. So `-F,`, `--field-separator=,`, and
`/F:,` are all equivalent.
.AWK PROGRAM LANGUAGE
An awk program is one or more pattern-action rules of the form:
PATTERN { ACTION }
Both PATTERN and ACTION are optional. A bare pattern with no action
defaults to `{ print }`. A bare action with no pattern runs on every
record. Rules are separated by newlines or semicolons.
BEGIN Runs once, before any input is read.
END Runs once, after all input is consumed.
BEGINFILE Runs before the first record of EACH input file.
FILENAME is already set and FNR is 0. If the file
could not be opened, this still runs, with ERRNO
describing why -- and `nextfile` here skips the file
instead of letting the error stop the run.
ENDFILE Runs after the last record of each input file. It
runs for a file cut short by `nextfile`, and for an
empty one, because those files still ended. It does
NOT run for a file that never opened, nor for the
file in hand when `exit` is called.
/REGEX/ Matches when the current record matches REGEX.
EXPR Matches when EXPR evaluates to a true value (any
non-zero number or non-empty string).
EXPR1, EXPR2 Range pattern: matches from a record where EXPR1
is true through the next record where EXPR2 is
true (inclusive). Ranges latch.
!PATTERN Negation: matches when PATTERN does not.
.FIELDS AND RECORDS
A record is a line by default. The record is split into fields by FS:
$0 The whole record.
$1, $2... Individual fields, 1-indexed.
$NF The last field.
$(NF-1) Second-to-last field, etc.
Assigning to a field updates $0 (joined with OFS); assigning to NF
truncates or pads the field list.
.BUILT-IN VARIABLES
NR Total record number across all inputs.
FNR Record number within the current file (resets on each).
NF Field count of the current record.
FS Input field separator (default: " ").
OFS Output field separator for `print` (default: " ").
ORS Output record separator for `print` (default: "\n").
RS Input record separator (default: "\n").
FILENAME Name of the current input file ("-" for stdin).
CONVFMT Format used when a NUMBER becomes a string in
CONCATENATION or as an array subscript (default "%.6g").
OFMT Format used when a number is printed by `print`
(default "%.6g"). CONVFMT and OFMT are separate knobs on
purpose: `x ""` and `print x` can differ.
NEITHER applies to an integral value -- 1e17 prints as
100000000000000000, not 1e+17, whatever they are set to.
ARGC Operand count, including ARGV[0].
ARGV ARGV[0] is "awk"; ARGV[1..] are the operands in the order
given -- file names AND var=value assignments -- so
`for (i = 1; i < ARGC; i++)` walks the inputs.
ENVIRON The process environment, keyed by variable name:
ENVIRON["PATH"]. Built on first use.
ERRNO Why the last input file failed to open, as text
("No such file or directory"), or empty when it opened.
Set before BEGINFILE runs, which is where it is meant to
be read.
RSTART Position of last regex match (set by match()).
RLENGTH Length of last regex match (-1 if no match).
SUBSEP Separator used to join a multi-dimensional subscript:
`a[i,j]` is one element keyed by i SUBSEP j. Default is
. Reassigning it changes the join, and
`split(key, parts, SUBSEP)` is how you take such a key
apart again. The join always used and the variable
was never published, so SUBSEP read as the empty string
and that split returned single characters.
getline Read the next record from the main input.
Sets $0, NF, NR, FNR.
getline var ...into var instead. Sets NR, FNR.
getline < file Read a record from file. Sets $0, NF.
getline var < file ...into var. Sets nothing else.
"cmd" | getline Run cmd, read a record of its output.
Sets $0, NF.
"cmd" | getline var ...into var. Sets nothing else.
Returns 1 when a record was read, 0 at end of input, and -1 when
the source could not be opened. The usual shape is therefore:
while ((getline line < "config.txt") > 0) { ... }
A plain `getline` shares the driver's position, so a record it
consumes is one the main loop will not see again -- which is what
makes `{ getline; print }` print every OTHER record.
That position spans every input operand, so a `getline` at the end
of one file rolls into the next: FILENAME changes, FNR restarts, NR
carries on, and the file being left gets its ENDFILE while the one
being entered gets its BEGINFILE. It returns 0 only at the end of
the LAST file.
Reads from the same source advance: two `getline < "f"` calls give
the first and second records. A source that fails to open keeps
returning -1 rather than being retried on every call.
The command forms do NOT move NR. That follows GNU, and diverges
from the POSIX table which lists NR for them; matching the standard
instead would disagree with every script written against gawk.
"cmd" runs through CSHW, so it reaches the same commands the rest of
the shell has -- builtins included, and whole pipelines:
"echo abc | rev" | getline r # r is "cba"
Nothing routes to cmd.exe or PowerShell unless system() is asked for
one by name.
.BUILT-IN FUNCTIONS
String:
length(s) Length in characters.
substr(s, start [, n]) Substring (1-indexed).
index(haystack, needle) 1-indexed position, 0 if not found.
split(s, arr [, sep]) Split into array, return field count.
sub(re, repl [, target]) Replace first match in target (default $0).
gsub(re, repl [, target]) Replace all matches.
match(s, re) Set RSTART/RLENGTH; return position.
tolower(s), toupper(s)
sprintf(fmt, ...) printf-style formatting; returns string.
Numeric:
int(x) Truncate to integer.
sqrt(x), exp(x), log(x)
sin(x), cos(x), atan2(y, x)
rand() Pseudo-random in [0, 1).
srand([seed]) Seed rand; default is wall-clock.
Time:
systime() Seconds since the Unix epoch.
Process and stream:
close(expr) Close a file or command opened by print
redirection or by getline. Returns 0 if
something was closed, -1 if that name was
never open.
system([shell, ] cmd) Run a command, wait, return its exit
status. See the SYSTEM section.
I/O:
print [arg, arg, ...] Output args joined by OFS, terminated by ORS.
printf fmt, args... printf-style; no trailing ORS unless in fmt.
printf conversions: %s %d %i %u %f %e %g %x %X %o %c %%
Flags: - + space 0 #
Width and precision may each be a number or `*`, which takes the
value from the next argument -- `printf "%*d", 5, 42` pads to five,
and `printf "%*.*f", 8, 2, x` takes both. The `*` form was
documented and never parsed; the literal text `%*d` came out.
%c prints the CHARACTER whose code is the argument when the argument
is a number, and the first character when it is a string. The
distinction is the value's origin, not how it looks: "65" is a
string and gives "6", while 0+65 gives "A". A numeric argument used
to take the string path and print its first digit.
Control flow: if/else, while, do/while, for(init;cond;step),
for (key in array), break, continue, next, nextfile, exit [N],
return.
next Stop processing this record; go to the next one.
nextfile Stop processing this record AND the rest of the
current input file; go on to the next file. On
standard input, where there is no next file, it ends
the input.
exit [N] Stop reading input and run END, then exit with N.
exit inside END stops immediately. A bare `exit`
leaves the status unchanged, so
`BEGIN{exit 3} END{exit}` still exits 3.
Arrays: associative; created by first reference. `delete arr[k]`
removes a single element; `delete arr` clears the whole array.
Membership is `key in arr`, and for a multi-dimensional subscript
`(i, j) in arr` -- which tests the same composite key `arr[i, j]`
creates.
Comments: `# ...` runs to end of line.
system([SHELL, ] COMMAND)
Runs COMMAND, waits for it, and returns its exit status. awk's own
buffered output is flushed first, so `print "a"; system("echo b")`
really does print a before b. The command's output goes wherever
awk's output goes, including into a `> file` redirection or a
captured pipeline.
The one-argument form runs COMMAND through CSHW. That is the more
compatible choice, not the parochial one: awk programs in the wild
are written against a Unix shell and call things like
system("rm -f " tmp), and cshw has rm where cmd.exe does not, so a
script ported from Unix stands a chance of running unchanged.
The two-argument form names the shell. Names are case-insensitive
and each shell answers to several spellings:
cshw | csh | cshell | tcsh the running cshw (the default)
cmd | command cmd.exe /c
ps | powershell | pwsh pwsh if present, else powershell
bash | sh bash.exe, if it is installed
system("ls -l") through cshw
system("cmd", "dir /w") through cmd.exe
system("ps", "Get-Process") through PowerShell
system("bash", "ls | wc -l") through bash
cshw is located by module path, not by PATH, so an awk script always
gets the same build of the shell that is interpreting it -- and a
portable install that is not on PATH still works.
The same routing applies to awk's own pipe operators, `print | "cmd"`
and `"cmd" | getline`. Those went to cmd.exe until 1.0.8.5, which
meant a cshw builtin was unreachable from inside a cshw script:
`echo abc | rev` worked at the prompt and answered "'rev' is not
recognized" inside awk.
bash is allowed to FAIL rather than fall back to another shell:
running bash syntax under cmd.exe would not report an error, it
would run something else. An unknown shell name is an error too.
.FIELD SPLITTING
Field splitting and split() are the same operation with different
destinations, and they follow one set of rules, decided in this
order:
FS == " " the default: split on runs of whitespace, with
leading and trailing whitespace ignored
FS == "" one field per character
one character LITERAL, never a regex -- which is what makes
FS="." split on dots rather than everywhere
anything longer an ERE
split(s, arr, sep) takes the same forms, and additionally accepts a
REGEX LITERAL, which is always treated as a regex whatever its
length:
split("a1b22c", A, /[0-9]+/) -> 3: "a", "b", "c"
split("a.b.c", A, ".") -> 3: "a", "b", "c"
split("abc", A, "") -> 3: "a", "b", "c"
An empty record has no fields under any separator, so NF is 0 and
split() returns 0.
.NUMBER FORMATTING
A value that is INTEGRAL always converts as an integer, and neither
OFMT nor CONVFMT applies to it. There is no magnitude cutoff:
print 1e17 -> 100000000000000000
print 2^53 -> 9007199254740992
A non-integral value uses OFMT in `print` and CONVFMT everywhere
else -- concatenation, array subscripts, comparison against a
string. Both default to "%.6g".
BEGIN { OFMT="%.2f"; CONVFMT="%.4f"; x = 3.14159
print x # 3.14 (OFMT)
print x "" # 3.1416 (CONVFMT)
}
Going the other way, a STRING becomes a number by reading a leading
decimal number and stopping. POSIX awk does not accept the hex,
infinity or nan spellings that C's strtod does:
"0x10" + 0 -> 0 (the number is 0; "x10" is trailing junk)
"inf" + 0 -> 0
"12abc"+ 0 -> 12
"1e3" + 0 -> 1000
awk '{ print $2 }' file.txt
Print the second whitespace-separated field of each line.
awk -F, '{ print $1, $3 }' data.csv
Print the first and third columns of a CSV file.
awk '/ERROR/ { print NR, $0 }' log.txt
Print line number and content for every line containing ERROR.
awk 'BEGIN { sum = 0 } { sum += $1 } END { print sum }' nums.txt
Sum the first column.
awk 'NR == 1 { next } { print }' file.txt
Skip the header row.
awk '{ count[$1]++ } END { for (k in count) print k, count[k] }' words.txt
Frequency table of the first column.
awk -F: '$3 >= 1000' /etc/passwd
Lines (entire record) where the third colon-separated field is >= 1000.
(Bare expression as pattern, no action: defaults to { print }.)
awk 'length($0) > 80' file.txt
Print lines longer than 80 characters.
awk 'BEGIN { OFS = "\t" } { print $2, $1 }' file.txt
Swap first two fields, output tab-separated.
awk -v threshold=100 '$1 > threshold' nums.txt
Filter using a command-line variable.
type access.log | awk '{ ip[$1]++ } END { for (i in ip) print ip[i], i }' | sort -rn
Top requesting IPs from a web log.
awk 'function f(a,b, t) { t = a + b; return t * 2 }
BEGIN { print f(3, 4) }'
A user-defined function. `t` is a LOCAL, because it is a
parameter the caller does not supply.
awk 'BEGIN { n = split("a1b22c", A, /[0-9]+/); print n, A[2] }'
Split on a regex. Prints "3 b".
awk 'BEGIN { system("cmd", "dir /w") }'
Run a command through cmd.exe rather than through cshw.
awk '{ print > ($1 ".txt") } END { for (f in seen) close(f) }'
Fan a file out into per-key files, closing each when done so
the handles are released.
awk 'FNR == 1 { print FILENAME; nextfile }' *.log
Print the first line of every file and skip the rest of each.
awk 'BEGIN { for (i = 1; i < ARGC; i++) print "input:", ARGV[i] }' a b
Walk the operands the program was given.
0 Successful completion. 1 At least one input file could not be opened. 2 awk program syntax error. N The exit N statement exited with status N.
Regex flavor: cshw's awk uses PCRE2 (Perl Compatible Regular Expressions). Anything you'd expect from `awk` plus features like lookahead / lookbehind, named groups, and Unicode classes all work.
PCRE2 runs with Unicode properties on, so [[:alpha:]], [[:upper:]] and [[:lower:]] match accented and non-Latin letters as POSIX says they should in a UTF-8 locale. Two classes are held to ASCII deliberately, because that is what awk means by them and what a program guarding arithmetic with /^[[:digit:]]+$/ is relying on:
[[:digit:]] 0-9 only. A fullwidth or Devanagari digit is [[:xdigit:]] not [[:digit:]], though it is [[:alnum:]].
Word boundaries follow awk, not Perl:
\b BACKSPACE, as in POSIX awk -- NOT a word boundary. \y The word boundary (gawk's spelling). \< \> Start and end of a word. \B Not a word boundary.
Field separator: The default FS = " " is special: it splits on runs of any whitespace (spaces and tabs) AND trims leading/trailing whitespace from the record before splitting. Any other FS value is used literally; multi-character FS is treated as a regex.
Numeric vs string comparison: awk types are dynamic. A value compares numerically if both operands look numeric (a numeric literal, or a string that fully parses as a number), otherwise comparison is lexicographic. To force string comparison, concatenate with the empty string: if (a "" == b "") # always string compare
User-defined functions: function name(arg1, arg2, local1, local2) { body }
Defined at the top level, alongside the pattern-action rules, and
callable from anywhere in the program -- including from a line
ABOVE the definition, which is what mutually recursive helpers
need. `return expr` yields a value; a bare `return`, or falling
off the end, yields the uninitialized value ("" or 0).
awk has no local declarations. The SURPLUS PARAMETERS are the locals: call with fewer arguments than the function names and the rest arrive uninitialized. The extra spaces conventionally written before them are a note to the reader and nothing to the parser.
Scalars are passed by VALUE and arrays by REFERENCE, decided by what the variable already holds rather than by the call site:
function bump(n, A) { n = 99; A["k"] = "set" }
BEGIN { x = 1; bump(x, arr); print x, arr["k"] } # 1 set
An argument that is still uninitialized has no type yet. If the function subscripts it, the caller gets the array back; if the function assigns it as a scalar, the caller is untouched.
A call requires the '(' hard against the name. With a space
between, `s (x)` is CONCATENATION of a variable and a parenthesized
expression -- the idiom behind every string-building loop in awk.
Built-in names may still be written with a space, as POSIX allows,
which is unambiguous because no user function may take one.
Recursion is supported to a depth of 1000 frames, which is far more than real programs use -- a descent over a million sorted items is 20 levels deep. Beyond it, awk reports "call depth exceeded" rather than overrunning the stack.
Deliberate differences from GNU awk: These are choices, not gaps. Each was measured against GNU Awk 5.0.0 and settled in favour of POSIX.
* \& and \\ in a sub()/gsub() replacement follow POSIX: \& inserts a literal &, and \\ a literal backslash. gawk warns about the first and keeps both characters for the second. * printf with fewer arguments than conversions treats the missing ones as "" and 0, which is what the original awk does. gawk makes it a fatal error. * ARGV[0] is "awk", which POSIX specifies. gawk puts its own name there. * The command forms of getline do not move NR. That follows GNU and diverges from the POSIX table, because matching the standard would disagree with every script written against gawk.
Unreadable input: An input file that cannot be opened stops the run: awk reports it, skips END, and exits 2 -- so a script cannot mistake a partial pass over its operands for a complete one. This follows gawk. The way to carry on regardless is the one gawk provides, a BEGINFILE rule that reads ERRNO:
awk 'BEGINFILE { if (ERRNO != "") nextfile }
{ ...work... }' *.log
Children and where their output goes: A child started by `print | "cmd"` writes to awk's own stdout when that is a terminal or a file, so its output appears live, interleaved with awk's.
When awk's stdout is a PIPE it cannot: cshw's builtins hand each other UTF-16 while a child writes plain bytes, and a stream carrying both is readable as neither. So in a pipeline the child's output is collected and re-emitted through awk's own writer, which puts one encoder in front of everything that leaves the process.
The visible consequence is WHEN it appears, not whether. Collected output is written at close time:
print "x" | "sort" # nothing yet
close("sort") # sort's output appears here
With close() the ordering is exactly what the program says, in every destination. Without it, a pipeline defers the child's output to the end of the run. To a terminal, output from a child that was never closed has always been timing-dependent -- it is a separate process and may not finish before awk does. close() is the answer in every awk, and this is what it is for.
system() and `"cmd" | getline` are unaffected either way.
Encoding: Input files are read as UTF-8 (with optional BOM stripped) and treated as wide-character internally. Programs that treat input as bytes (e.g. via length() on a multi-byte sequence) get character counts, not byte counts.
barrier back to top ↑rendezvous barrier for N participants
barrier <name> create <count>
barrier <name> wait [/timeout:ms]
barrier <name> reset
barrier <name> status
barrier <name> destroy
A named barrier that releases all participants at once when <count> of them have called wait -- a rendezvous point for a fan-out of coroutines. Create it with the participant count before use; waiting on an unknown name is an error.
create <count> Create a barrier for count participants.
wait [/timeout:ms] Block until all arrive; $? = 0 passed, 1 timeout.
reset Reset for reuse.
status Show waiting count and total.
destroy Remove the barrier.
ON FAILURE
`wait` is FATAL. A barrier's whole guarantee is "nobody proceeds until everybody
arrives"; timing out and continuing does not weaken that guarantee, it deletes
it, and does so for the one participant that then races ahead of a cohort still
waiting behind it. There is deliberately no `trywait`: arriving at a barrier and
then leaving corrupts the count for everyone else, so the honest options are to
wait or to stop.
barrier start create 3
corunproc phase1 ; corunproc phase2 ; corunproc phase3
# each worker calls: barrier start wait (all resume together)
0 Operation succeeded (wait: barrier passed). >0 Wait timeout, unknown name, or bad usage.
base back to top ↑print a number in another radix
base RADIX NUMBER...
Prints each NUMBER in RADIX, which may be 2 through 36.
cshw reads numbers in several radices -- `@ x = 0x100` is 256 here, where tcsh answers "Badly formed number" -- and `base` is the other half of that: a way to write them back out.
NUMBER is read in the shell's usual conventions: plain decimal, or a `0x`, `0b` or `0o` prefix, with an optional sign. The same forms `@` accepts.
RADIX The output radix, 2 to 36. Digits above 9 are A-Z.
NUMBER One or more integers to convert.
Output for radix 2, 8 and 16 carries the prefix that reads back as the same
number, so the pair is closed:
set h = `base 16 48879` # 0xBEEF
@ back = $h # 48879
Other radices have no conventional prefix and are printed bare, so `base 36
48879` is `11PR` and a reader has to be told the radix -- which is true of
base 36 everywhere, not a limitation of this command.
A LEADING ZERO IS NOT OCTAL. `010` is ten, both here and in tcsh -- csh arithmetic is plain base 10, and C's rule does not apply. Write `0o10` for eight. This matters because zero-padded numbers are ordinary in scripts (dates, times, counters), and reading them as octal would silently change what they mean.
An integer whose digits do not belong to its prefix -- `0b12`, `0xZZ` -- is an error rather than a truncated value.
base 10 0x100
256
base 16 255
0xFF
base 2 11
0b1011
base 8 64
0o100
base 36 1295
ZZ
base 16 48879 -255
0xBEEF
-0xFF
0 All numbers converted.
1 A radix outside 2-36, or an operand that is not an integer.
The operand is named; it is not silently skipped.
base64 back to top ↑encode or decode base64 data
base64 [options] [FILE]
base64 -s TEXT
command | base64 [options]
Encodes binary data to base64 text or decodes base64 text back to binary. Base64 is commonly used for encoding binary data in text-based formats like JSON, XML, email attachments, and data URIs.
The operand is a FILE, not a string: `base64 notes.txt` encodes the contents of notes.txt. To encode literal text, use -s, or pipe it in. With no file and no -s, base64 reads standard input.
FILE File to encode/decode. Same as -i FILE.
-e, --encode Encode (the default).
-d, --decode Decode base64 input to binary output.
-i, --input FILE
Read input from FILE.
-o, --output FILE
Write output to FILE instead of standard output.
-s, --string TEXT
Encode the literal TEXT (UTF-8) rather than a file.
-w N Wrap encoded lines at N characters (default: 76,
0 for no wrap).
An unrecognized option is an error, not a silent no-op.
base64 image.png
Encode image.png to base64.
base64 -d encoded.txt > decoded.bin
Decode a base64 file to binary.
base64 -s "Hello World"
Encode literal text.
echo "Hello World" | base64
Encode text arriving on stdin.
echo "SGVsbG8gV29ybGQ=" | base64 -d
Decode base64 text.
base64 -w 0 file.bin
Encode without line wrapping.
base64 -e -i binary.exe -o encoded.txt
base64 -d -i encoded.txt -o decoded.bin
Round-trip through files without touching the pipeline.
0 Success
1 Input was not valid base64 (decode mode), the file could
not be opened or written, or an option was unrecognized
Character Set: Base64 uses A-Z, a-z, 0-9, +, / and = for padding. URL-safe base64 uses - and _ instead of + and /.
Decoding is checked: Input that is not valid base64 is refused rather than decoded to whatever the bytes happened to mean.
Size Increase: Base64 encoding increases data size by approximately 33%.
Binary Safety: Base64 ensures binary data can be safely transmitted through text-only channels.
Common Uses: - Embedding images in HTML/CSS (data URIs) - Encoding credentials for HTTP Basic Auth - Encoding binary data in JSON - Email attachments (MIME)
basename back to top ↑strip directory and suffix from a path
basename <path> [suffix]
Print <path> with any leading directory components removed. Both forward slashes and backslashes are recognized as path separators, and trailing separators are ignored.
If a second argument is given it is treated as a suffix: when the result ends with that suffix, the suffix is removed as well -- but only when doing so still leaves a non-empty name.
basename does not touch the filesystem; it is a pure text operation on the path you give it.
basename /usr/lib/file.txt
Prints: file.txt
basename /usr/lib/file.txt .txt
Prints: file
basename C:\Tools\cshw\cshw.exe .exe
Prints: cshw
basename /usr/lib/
Prints: lib (the trailing slash is ignored)
Zero on success. basename with no path argument is a usage error.
bc back to top ↑arbitrary-precision calculator language
bc interactive REPL (reads from stdin)
bc "EXPR_OR_PROGRAM" run source from argv
bc -e "EXPR" [-e "EXPR"...] inline expression (repeatable)
bc -f FILE [-f FILE...] script from file (repeatable)
bc -i force REPL even with redirected stdin
bc -l silently accepted (lib always loads)
bc -x | --exact exact rational + Power arithmetic
bc -c | --complex complex-number arithmetic
bc --lex "SRC" debug: dump token stream
bc --parse "SRC" debug: dump AST tree
bc is the POSIX arbitrary-precision calculator language. cshw's implementation uses Gavin Howard's BCL (BSD 2-clause) for the arithmetic backend and a hand-written lexer, parser, and tree-walking interpreter for the language surface.
Numbers are arbitrary-precision decimal -- no float-format loss, no silent overflow. The current `scale` variable controls how many fractional digits division and the math library produce; `ibase` and `obase` control the input and output bases. Defaults: scale=20, ibase=10, obase=10.
bc is a real little programming language: statements, expressions, variables, sparse arrays, user-defined functions with `auto` locals, recursion, control flow (if / else / while / for, with break and continue), and a standard math library (loaded automatically).
Expression operators, low to high precedence:
= += -= *= /= %= ^= assignment (right-associative)
|| && short-circuit logical
< <= == != >= > relational
+ - additive
* / % multiplicative
- unary minus (binds LESS tight than ^)
^ power (right-associative)
! ++ -- logical-not, prefix increment/decrement
++ -- postfix increment/decrement
primaries NUMBER, NAME, NAME[expr], NAME(args),
(expr), built-in calls
Numbers may use digits 0-9 plus A-Z when ibase > 10 (A=10, B=11, ...).
A standalone uppercase letter is always its constant value (so
`ibase=A` is the canonical idiom for "set base 10 regardless of
current base").
Statements: blocks { ... }, if (cond) stmt [else stmt],
while (cond) stmt, for (init; cond; step) stmt, break, continue,
halt, quit, return [VALUE], print ITEM [, ITEM...], define
[void] NAME(PARAMS) { [auto LOCALS;] BODY }. A bare expression
statement prints its value and updates `last` (unless inside a
function body).
Comments: /* block */ and # to end-of-line. Backslash-newline is
line continuation inside numbers.
.MATH LIBRARY
Loaded automatically. POSIX names:
e(x) e^x
l(x) natural log
s(x) sine
c(x) cosine
a(x) arctangent
j(n, x) Bessel function of the first kind, order n
cshw friendly aliases:
sin(x) cos(x) tan(x)
asin/acos/atan via a()
atan2(y, x)
exp(x) ln(x)
log(x) log10(x) log2(x)
pi()
bc "1 + 2 * 3" -> 7
bc -e "scale=50; 1/3" -> .3333... (50 digits)
bc -f myscript.bc run a script file
bc "define f(n){if(n<2)return n; return f(n-1)+f(n-2)}; f(20)"
-> 6765 (recursive fib)
bc "for(i=1;i<=10;i++) i*i" -> 1 4 9 16 ... 100
bc "pi()" -> 3.14159...
bc "sin(pi()/2)" -> 1.000...
bc drop into interactive REPL
.EXACT MODE (-x, --exact)
With `-x` / `--exact`, integer literals stay integer and rational
arithmetic preserves p/q form: `bc -x "1/3 + 1/6"` prints `1/2`, not
`.4999...` truncated. Plus a Power(rational, rational) layer carries
sqrt and powers symbolically:
bc -x "1/3 + 1/6" -> 1/2
bc -x "5/15" -> 1/3 (auto-reduced)
bc -x "2^10" -> 1024 (integer fold)
bc -x "(1/2)^2" -> 1/4
bc -x "sqrt(2)" -> 2^(1/2) (symbolic)
bc -x "sqrt(2) * sqrt(2)" -> 2 (same-base fold)
bc -x "x = 1/3; y = 1/6; x+y" -> 1/2 (variables work)
Operations that preserve form stay exact; anything else falls through
to BCL's scaled-decimal. This is NOT a CAS:
bc -x "sqrt(2) + sqrt(3)" -> 3.14626436... (no symbolic sum)
bc -x "sin(1)" -> .84147098... (transcendentals)
The contract is "exact when possible," not "always exact."
.EXACT-MATRIX TIER (1.0.6.4)
Within `-x` mode, bc also handles small matrices of exact rationals.
Matrix literals use bracketed-list syntax `[[a, b], [c, d]]`; arithmetic
+ - * works between matrices (with dimension checks); scalar * matrix and
matrix * scalar broadcast a Rational across all entries; matrix / scalar
divides by a Rational. Built-in functions:
det(M) determinant (M must be square)
transpose(M) the obvious thing
inverse(M) via Gauss-Jordan elimination over rationals
(M must be square and non-singular)
mget(M, i, j) element at row i, col j (0-indexed)
mset(M, i, j, v) return a new matrix with entry (i,j) replaced
rows(M) / cols(M) dimensions
Examples:
bc -x "[[1, 2], [3, 4]] * [[5, 6], [7, 8]]" -> [[19, 22], [43, 50]]
bc -x "det([[6, 1, 1], [4, -2, 5], [2, 8, 7]])" -> -306
bc -x "inverse([[4, 7], [2, 6]])" -> [[3/5, -7/10], [-1/5, 2/5]]
bc -x "m = [[1, 2], [3, 4]]; m * inverse(m)" -> [[1, 0], [0, 1]]
The entries stay exact rational through every step -- inverse() produces
a rational matrix whose entries are arbitrary p/q. There is no numerical
linear algebra (no LU/QR/SVD, no eigenvalues). This is "symbolic exact
linear algebra for small matrices", not a NumPy replacement. For matrices
larger than about 6x6, the cofactor-expansion determinant slows down;
for floating-point matrix work, shell out to Python or MATLAB.
- Variable names: bc inherits BCL's base-36 number parsing, so uppercase
single letters A-Z lex as numbers (M = 22, T = 29, I = 18, etc.). Use
lowercase identifiers for matrix variables: `m = [[...]]` works,
`M = [[...]]` does not (M is parsed as the literal 22). Same gotcha
applies to complex-mode imaginary literals (use `cplx(0, 1)`, not `I`).
- Matrix literals are only valid in `-x` mode. Outside `-x`, attempting
one raises a runtime error.
.COMPLEX MODE (-c, --complex)
With `-c` / `--complex`, bc gains complex-number arithmetic via four
lowercase built-ins: `cplx(re, im)` constructs `re + im*i`, `re(z)`
and `im(z)` extract the real and imaginary parts, `conj(z)` returns
the conjugate, and `abs(z)` returns the magnitude. The imaginary
unit is `cplx(0, 1)` (lowercase function names dodge BCL's base-36
number parsing -- `I` would lex as 18, not an identifier).
bc -c "cplx(0, 1) * cplx(0, 1)" -> -1
bc -c "cplx(1, 2) + cplx(3, 4)" -> 4+6i
bc -c "cplx(3, 4) * cplx(1, 2)" -> -5+10i
bc -c "(cplx(1, 1)) / cplx(1, -1)" -> i
bc -c "sqrt(cplx(-4, 0))" -> 2i
bc -c "abs(cplx(3, 4))" -> 5
bc -c "conj(cplx(3, 4))" -> 3-4i
Equality (`==` / `!=`) is defined structurally on complex values.
Ordering (`<` / `>` / `<=` / `>=`) raises a runtime error -- complex
numbers have no total order. `-c` composes with `-x`: real and imag
parts are decimal even in `-x -c`, but rational-only arithmetic on
real inputs stays exact as usual.
Output format: `a+bi` with the obvious shortcuts -- the zero terms
are dropped (`5i` not `0+5i`), unit coefficients omit the `1` (`3+i`
not `3+1i`), and negative imaginary parts use `-` not `+-` (`3-4i`).
With no inline source and a TTY stdin, bc enters an interactive REPL
showing `bc> ` for new statements and `... ` for continuation lines.
Multi-line definitions accumulate until braces balance. Use `quit`
or `halt` to return to cshw. `-x` and `-c` apply to the REPL too.
.SEE ALSO
dc(1) the RPN sibling
@ (cshw builtin) inline csh arithmetic with float primitives
Implementation: BCL (Gavin Howard's bc, BSD 2-clause) for arithmetic backend; cshw-written lexer / parser / interpreter for the language. The math library is a verbatim copy of Gavin's lib.bc; the alias layer (sin, cos, pi, ...) is cshw's own.
bg back to top ↑move job to background
bg [%JOBID]
Resumes a stopped job and runs it in the background. If no job ID is specified, operates on the current job.
Resuming a job that is ALREADY running succeeds and does nothing, the same way `stop` on an already-stopped job does. It used to report "could not resume job N" at status 1.
%JOBID Job number (from jobs command).
bg
Resume current job in background.
bg %1
Resume job 1 in background.
# Common workflow:
longcommand
# Press Ctrl+Z to stop
bg
# Now it runs in background
0 Success 1 No such job 2 Job cannot be backgrounded
Typical Workflow: 1. Start a command 2. Press Ctrl+Z to suspend it 3. Type 'bg' to continue in background 4. Use 'fg' later to bring back to foreground
Output: Backgrounded processes may still produce output to the terminal. Consider redirecting output when backgrounding.
bindevent back to top ↑bind a script proc as a window event handler
bindevent <hwnd> <kind> [<args>] <procname>
Records a script-proc handler for a Win32 message on a given window. Whitelisted messages are routed through CSHW's dispatcher; on the next matching event, the bound proc runs.
All handlers except `close` fire as coroutines (off the UI thread, so the UI stays responsive). `close` handlers run synchronously on the UI thread -- returning a truthy $result vetoes the close.
`$hwnd` is set to the originating window for the handler's duration.
<hwnd> Target HWND in hex or decimal. Must satisfy IsWindow().
<kind> One of:
command <ctlId> WM_COMMAND from <ctlId>
$1=ctlId $2=notifyCode
notify <ctlId> WM_NOTIFY from <ctlId>
$1=ctlId $2=notifyCode
timer <timerId> WM_TIMER
$1=timerId
close WM_CLOSE (SYNCHRONOUS, $result vetoes)
destroy WM_DESTROY
lbuttondown WM_LBUTTONDOWN $1=x $2=y
lbuttonup WM_LBUTTONUP $1=x $2=y
keydown <vk> WM_KEYDOWN $1=vk
size WM_SIZE $1=width $2=height
<procname> Proc to invoke. Must already be defined via `proc`.
proc on_ok
echo "OK clicked"
endproc
bindevent $w command 100 on_ok
proc veto_close
share user_clicked_x = 1
return 1 # veto -- window stays open
endproc
bindevent $w close veto_close
proc on_size
echo "resized to ${1}x${2}"
endproc
bindevent $w size on_size
0 Binding installed. 1 Bad HWND, unknown kind, missing args, or undefined proc.
WM_CLOSE handlers run synchronously on the UI thread. Slow handlers stall the UI; do not call dialog APIs (passworddlg, messagebox, etc.) from a close handler -- it deadlocks.
For windows NOT created by `createwindow` (e.g., one returned by a future `findwindow`, or a plugin-class window), CSHW installs a SetWindowSubclass shim on first bind so the binding actually receives messages.
unbindevent, createwindow, addcontrol, sendmessage, postmessage
bugreport back to top ↑compose and send a bug report to bugs@tropibyte.com
bugreport
bugreport "subject"
bugreport "subject" "details"
Open a bug-report email composed in your default mail client, addressed to bugs@tropibyte.com. With no arguments, presents a modal dialog to collect a subject line and free-text details. With one or two string arguments, skips the dialog and goes straight to the mail client.
Nothing is sent until you click Send. cshw only opens the composer -- you remain in control of the final message.
By default, three diagnostic lines are appended to the body: - cshw version (from the binary's VS_VERSION_INFO resource) - Windows version + build number - Last shell error code, if any
The dialog has a checkbox to suppress those. The two- and three-argument forms always include them.
"subject"
Short summary of the bug. Used as the email Subject line, with
"cshw bug: " prepended.
"details"
Free-text body. Multi-line OK. Pre-formatted; mail clients
respect the line breaks.
bugreport
Open the modal dialog.
bugreport "foreach hangs on empty list"
Compose with just a subject. Body will contain only the
diagnostics tail.
bugreport "sed -i fails" "sed -i s/a/b/ file.txt returns error 5"
Subject + body, no dialog.
0 Mail client opened successfully. 1 Dialog cancelled, or ShellExecute failed.
The mail client is selected by the system's default mailto: handler -- typically Outlook, Thunderbird, the Windows Mail app, or a webmail handler that registered itself. If no handler is registered, the command fails with a hint pointing at bugs@tropibyte.com directly.
The web equivalent (no cshw installed) is https://tropibyte.com/bugs.html which presents the same fill-in-the-blanks mailto: template.
cancel back to top ↑remove jobs from a print queue (System V spelling of lprm)
cancel [-d PRINTER] JOBID...
cancel [-d PRINTER] -a
The System V name for lprm. They are the SAME command in cshw, with the same options and behaviour; both accept -d and -P.
See lprm(1) for the full description.
cancel 17
cancel -a
cancel -d "Front Desk" 12 13
0 Every named job was removed 1 At least one could not be
cat back to top ↑concatenate file(s) (or stdin) to standard output
cat [options] [file...]
cat [options] - [file...]
command | cat [options]
Concatenates one or more files (or standard input) to standard output. With no file argument, or when file is '-', cat reads from standard input.
cshw's cat folds together the GNU coreutils, BSD, AIX, and Solaris feature sets so users moving between shells keep their muscle memory. Long-form (--number), short-form (-n), and cshw-style (/n) switches are all accepted.
cat is encoding-aware on input: UTF-16 LE/BE and UTF-8 BOMs are detected and decoded automatically; otherwise input is read as the active code page.
-n --number Number all output lines, right-justified in 6
columns followed by a TAB.
-b --number-nonblank Number non-empty lines only. Overrides -n.
-s --squeeze-blank Collapse runs of consecutive blank lines into
a single blank line.
-E --show-ends Print '$' at the end of each line.
-T --show-tabs Print TAB characters as '^I'.
-v --show-nonprinting Print control characters and high-bit bytes
using ^X / M-X notation. LF and TAB are not
affected unless -E or -T is also given.
-A --show-all Equivalent to -vET.
-e Equivalent to -vE.
-t Equivalent to -vT.
-q --quiet Silent on missing files (AIX behavior).
-u Accepted for POSIX compatibility (no-op:
cshw's stdout is line-buffered already).
- Read standard input at this position.
-- End of options; remaining tokens are files.
cat file.txt
Print the file to stdout.
cat file1.txt file2.txt > combined.txt
Concatenate two files into a third via redirection.
cat -n script.cshw
Number every line.
cat -b notes.md
Number only non-blank lines.
cat -s log.txt
Squeeze consecutive blank lines so the output is denser.
cat -A weird.txt
Reveal all non-printing structure: tabs as ^I, line ends as $,
control bytes as ^X / M-X.
ls | cat -n
Number a piped stream.
cat - file.txt
Read from stdin first, then file.txt.
cat -q maybe_missing.txt always_present.txt
Don't error if maybe_missing.txt isn't there (AIX-style).
0 Success >0 One or more files could not be read (unless -q was given)
Encoding: Input files with a UTF-16 LE BOM, UTF-16 BE BOM, or UTF-8 BOM are decoded into wide characters. Files without a BOM are interpreted as the active code page (CP_ACP). The output stream is wide-aware so redirection and piping preserve characters.
Stream order: Files are emitted in the order given on the command line. With -n or -b, line numbers continue across file boundaries (one logical concatenated stream), matching standard cat behavior.
-s with non-empty lines: -s only collapses fully empty lines (or CR-only lines). It does not strip whitespace from non-empty lines.
Difference from type: 'type' is cshw's DOS-style file-display command and takes no options. 'cat' is the Unix-style equivalent with the full option surface above.
cd back to top ↑change the current working directory
cd [directory]
cd [options]
chdir [directory]
Aliases: chdir
Changes the shell's current working directory. If no directory is specified, displays the current directory path. The cd command supports both absolute and relative paths, as well as several special keywords.
When changing to a new directory, CSHW maintains a per-drive directory cache, allowing you to return to the last directory on each drive by specifying just the drive letter.
The cd command also integrates with the shell's alias system, so you can create shortcuts to frequently accessed directories.
directory The path to change to. Can be absolute or relative.
Special values:
- Change to the previous directory (like UNIX cd -)
~ Change to the user's home directory (%USERPROFILE%)
.. Change to the parent directory
... Change to the grandparent directory (two levels up)
.... Change to three levels up (and so on)
system Change to %SystemRoot% (usually C:\Windows)
windows Change to %SystemRoot% (usually C:\Windows)
Drive letters:
D: Change to drive D: and restore the last directory on that drive
cd
Display the current working directory.
cd C:\Users\Public
Change to an absolute path.
cd ..
Change to the parent directory.
cd ...
Change up two directory levels.
cd ~
Change to your home directory (%USERPROFILE%).
cd -
Return to the previous working directory.
cd system
Change to the Windows system directory (C:\Windows).
cd D:
Switch to drive D: and restore the last working directory on that drive.
cd "Program Files"
Change to a directory with spaces in the name (quoted).
0 Success - directory was changed 1 Directory not found 2 Invalid argument or syntax error
USERPROFILE Used when cd ~ is invoked SystemRoot Used when cd system or cd windows is invoked
$cdpath: When a bare relative name is not in the current directory, cd looks for it under each directory in $cdpath:
set cdpath = (~/projects /usr/local/src) cd myapp # finds ~/projects/myapp
cd prints the directory when cdpath is what found it, so it is visible that `cd myapp` did not mean ./myapp. A name that says where to look -- absolute, or starting with . or .. -- is taken at its word and does not consult cdpath. $cdpath was accepted and ignored before: cd reported "file not found" and, worse, left the shell where it was, so a script that carried on with relative paths operated on the wrong directory.
CSHW maintains a separate current directory for each drive letter. When you switch drives using just the drive letter (e.g., cd D:), the shell restores your previous position on that drive.
The command 'chdir' is an alias for 'cd' and works identically.
Unlike cmd.exe, CSHW's cd command supports the UNIX-style cd - to return to the previous directory.
chancreate back to top ↑create a message-passing channel (shorthand)
chancreate <name> [capacity]
Shorthand for `channel <name> create [capacity]`. capacity 0 (or omitted) creates an unbounded channel where send never blocks. Use the channel command for send/receive/close/status/destroy.
chancreate results # unbounded
chancreate work 16 # bounded to 16 buffered messages
0 Created. >0 Bad usage.
channel back to top ↑message-passing channel between coroutines
channel <name> create [capacity]
channel <name> send <message>
channel <name> receive [/timeout:ms]
channel <name> tryreceive
channel <name> close
channel <name> status
channel <name> destroy
channel <operation> <name> [args] (either order works)
A named CSP-style channel carrying string messages between coroutines and threads. capacity 0 (or omitted) is unbounded (send never blocks); a bounded channel blocks send when full. receive and tryreceive set $result to the message. send fails on a closed channel. Create before send/receive; either `channel <name> <op>` or `channel <op> <name>` order is accepted.
create [capacity] Create the channel (0 = unbounded).
send <message> Enqueue a message (remaining words are joined).
receive [/timeout:ms] Dequeue, blocking; sets $result; $? = 0 got, 1 timeout/closed.
tryreceive Non-blocking dequeue; sets $result; $? = 0 got, 1 empty.
close Close for sending (receivers still drain the buffer).
status Show count, capacity, and closed state.
destroy Remove the channel.
EXIT STATUS OF receive
0 a message was received; it is in $result
1 end of stream -- the channel is closed and drained
2 timed out waiting; the channel is still open and more may arrive
1 and 2 used to be the same answer, so a consumer could not tell "we are done"
from "I gave up waiting" and a slow producer looked exactly like a finished one.
Both are non-zero, so the usual drain loop is unaffected:
while (1)
channel c receive
if ($status != 0) break
...
end
`receive` is deliberately NOT fatal, unlike `semaphore acquire` or `event wait`:
reaching the end of a channel is a normal outcome, not a failure.
chancreate work 10 # == channel work create 10
channel work send "task-1"
channel work receive
echo $result
0 Operation succeeded (receive: got a message). >0 Receive timeout/empty, send on closed, unknown name, or bad usage.
chancreate, semaphore, mutex, event, barrier, sync, corunproc
chdir back to top ↑change the current working directory (alias for cd)
chdir [directory]
`chdir` is identical to `cd`. See `man cd` for full documentation, options, and examples.
checkmail back to top ↑check $mail now for new messages
checkmail
Forces the same new-mail check cshw runs automatically before each interactive prompt. The mailboxes and poll interval come from the $mail variable:
set mail = (interval path ...)
where a leading number is the poll interval in seconds (0 disables automatic checking) and each path is either a Maildir directory (new mail = a change in the count of *.eml files) or an mbox file (new mail = the file grew). When a mailbox has grown since the last check, checkmail prints "You have new mail for user: <name>".
set mail = (60 ~/Maildir/new)
checkmail
0 Check performed (whether or not new mail was found).
set, imap, pop3
chmod back to top ↑change file permissions
chmod MODE FILE
chmod [options] MODE FILE...
Changes file access using UNIX mode syntax, mapped onto the two things Windows actually checks: the read-only attribute and the NTFS access control list.
An OCTAL mode writes a real ACL, one entry per class -- owner, primary group, and Everyone for "other". r grants read, w grants write and delete, x grants FILE_EXECUTE. `chmod 700` really does exclude everyone but the owner, and `chmod 444` really does refuse a write.
A mode that withholds access from the owner is enforced with DENY entries. Windows grants the UNION of every matching ALLOW entry, and on a workgroup machine the owner is frequently also the primary group, so without them `chmod 466` -- owner read-only, other read-write -- would hand the owner write access straight back through Everyone.
A SYMBOLIC mode answers one question, may this file be written, and sets or clears the read-only attribute. Per-principal forms (u+w, o-r) are accepted but affect that same single question; reach for an octal mode when you need per-class control.
The two forms compose. Windows checks the attribute and the ACL independently and a write needs BOTH to permit it, so each form keeps the other in step: once an octal mode governs a file a later +w or -w edits the ACL, and an octal mode sets or clears read-only to match the owner's write bit. Without that, `chmod -w f` followed by `chmod 644 f` reported success twice and left the file unwritable.
THE EXECUTE BIT DOES NOT DECIDE WHAT RUNS. Windows decides that from the file extension and PATHEXT, so `chmod +x notes.txt` will not make notes.txt runnable -- no shell on Windows can make that true. It is not ignored either: x grants or withholds FILE_EXECUTE, so `chmod 644 tool.exe` will stop tool.exe from launching.
MODE Permission mode (numeric or symbolic).
FILE File(s) to modify.
Numeric mode (octal):
400 Owner read
200 Owner write
100 Owner execute
040 Group read
020 Group write
010 Group execute
004 Others read
002 Others write
001 Others execute
Symbolic mode:
u User (owner)
g Group
o Others
a All (ugo)
+ Add permission
- Remove permission
= Set exact permission
r Read
w Write
x Execute
Options:
-R, --recursive Apply recursively.
-v, --verbose Verbose output.
chmod 644 file.txt
Owner read/write, others read-only.
chmod 755 script.exe
Owner full, others read/execute.
chmod +x script.bat
Add execute permission.
chmod -w readonly.txt
Remove write permission (make read-only).
chmod u+w,go-w file.txt
Owner writable, others not.
chmod -R 755 directory/
Recursively set permissions.
0 Success 1 File not found 2 Access denied 3 Invalid mode
Windows Mapping: UNIX permissions don't map directly to Windows. chmod primarily: - Sets/clears read-only attribute (write permission) - Modifies NTFS ACLs where possible
Read-Only: The most common use is toggling read-only: chmod -w file.txt # Make read-only chmod +w file.txt # Make writable
Execute Permission: On Windows, execute permission is determined by file extension, not a permission bit. chmod +x has limited effect.
NTFS ACLs: For full Windows permission control, use icacls or the attrib command for attributes.
Scripts: chmod is useful for cross-platform scripts that expect UNIX permission syntax.
chown back to top ↑change file owner
chown OWNER FILE
chown OWNER:GROUP FILE
chown [options] OWNER FILE...
Changes the owner of files and directories. On Windows, this modifies the file's security descriptor to set a new owner.
OWNER New owner (username or SID).
GROUP New group (optional, after colon).
FILE File(s) to modify.
-R, --recursive Apply changes recursively to directories.
-v, --verbose Show files as they're processed.
chown Administrator file.txt
Change owner to Administrator.
chown DOMAIN\User document.docx
Change owner to domain user.
chown -R Administrator C:\Data
Recursively change owner of directory tree.
chown "NT AUTHORITY\SYSTEM" service.exe
Change owner to SYSTEM account.
0 Success 1 File not found 2 Access denied (need Administrator) 3 Invalid owner
Administrator Required: Changing file ownership typically requires Administrator privileges or SeRestorePrivilege/SeTakeOwnershipPrivilege.
Taking Ownership: Administrators can take ownership of any file even if current permissions deny access.
Windows vs UNIX: - UNIX chown: Changes owner and optionally group - Windows: Owner is part of security descriptor, groups work differently
Security Descriptors: File ownership is part of Windows NTFS security. The owner has special privileges including the ability to modify permissions.
SIDs: You can specify owners by Security Identifier (SID) instead of name: chown S-1-5-18 file.txt # SYSTEM
clip back to top ↑copy to clipboard
clip < FILE
command | clip
clip [options]
Copies text from standard input to the Windows clipboard. The copied content can then be pasted into any application.
Standard input is copied to clipboard.
/p Paste clipboard contents to stdout (read clipboard).
dir | clip
Copy directory listing to clipboard.
type file.txt | clip
Copy file contents to clipboard.
echo "Hello" | clip
Copy text to clipboard.
clip /p
Display current clipboard contents.
clip /p > saved.txt
Save clipboard to file.
grep error log.txt | clip
Copy matching lines to clipboard.
0 Success 1 Clipboard access error
Text Only: clip works with text data. Binary data will be treated as text and may not produce expected results.
Unicode: Unicode text is supported and preserved.
Integration: clip is useful for copying command output to paste elsewhere: - Copy file paths for email - Copy command output for documentation - Copy error messages for searching
cls back to top ↑clear the console screen
cls [/scroll]
Clears the console screen and moves the cursor to the home position (top-left corner).
By default, cls erases the entire console buffer including all scrollback history. The screen is completely cleared.
/scroll, /s, -scroll, -s
Preserve scrollback buffer. Instead of erasing the buffer,
content is scrolled up and filled with blank lines. You can
still scroll back to see previous output.
cls
Clear the screen and erase all scrollback history.
cls /scroll
Clear the visible screen but preserve scrollback buffer.
cls /s
Same as cls /scroll.
0 Success
Alternative Names: Some systems use 'clear' instead of 'cls'. CSHW supports both.
Windows 10+ Required: The default erase behavior uses VT100 escape sequences which require Windows 10 or later. On older systems, the behavior may fall back to scroll mode.
echo, clear
cmdliblist back to top ↑list loaded command libraries
cmdliblist
cmdliblist /verbose
Displays information about all currently loaded command libraries. Shows library name, version, prefix, path, and command count.
With the /verbose option, also lists all commands provided by each library and indicates which ones shadow intrinsic commands.
/verbose Show detailed command list for each library.
/v Short form of /verbose.
cmdliblist
List all loaded libraries with basic info.
cmdliblist /v
List libraries with all their commands.
For each library, displays:
- Library name (or path if no name)
- Version (if specified by plugin)
- Prefix and whether it's required
- Full DLL path
- Number of commands registered
With /verbose, also shows:
- Each command name
- Command description
- Whether it shadows an intrinsic command
0 Always succeeds
cocancel back to top ↑cancel a running coroutine
cocancel <coid> | /all
Requests cancellation of a running coroutine (or every coroutine with /all). Cancellation is cooperative: the coroutine stops at its next checkpoint, so a coroutine that never yields may not stop immediately.
cocancel $coid
cocancel /all
0 Cancellation requested. >0 Unknown coroutine id.
cocas back to top ↑atomic compare-and-swap on a thread-safe variable
cocas <name> <expected> <newvalue>
Atomically sets the atomic variable name to newvalue only if its current value equals expected (string comparison; an unset variable compares as ""). Sets $? to 0 if the swap happened, 1 if not -- the primitive for lock-free retry loops across coroutines.
coset state idle
cocas state idle busy # $? = 0, state is now busy
cocas state idle busy # $? = 1, no change
0 Swapped (current value matched expected). 1 Not swapped (mismatch). >1 Bad usage.
coclean back to top ↑remove completed coroutines from tracking
coclean
Drops finished coroutines from the tracking table, freeing their ids and stored results. Read any results you still need with coresult first.
wait
coclean
0 Always.
codecr back to top ↑atomically decrement a thread-safe variable
codecr <name> [amount]
Atomically subtracts amount (default 1) from the integer value of the atomic variable name (see coset), and stores the PREVIOUS value in $result -- a fetch-and-subtract. An unset variable is treated as 0.
coset remaining 10
codecr remaining # $result = 10, remaining is now 9
0 Decremented. >0 Bad usage.
coget back to top ↑read a thread-safe atomic variable
coget <name>
Reads name from the atomic-variable table (see coset) and stores it in $result; an unset name yields the empty string. These atomic variables are distinct from ordinary `set` shell variables.
coset total 0
coincr total
coget total
echo $result
0 Always (unset name gives "").
coincr back to top ↑atomically increment a thread-safe variable
coincr <name> [amount]
Atomically adds amount (default 1) to the integer value of the atomic variable name (see coset), and stores the PREVIOUS value in $result -- a fetch-and-add. An unset variable is treated as 0. Safe to call concurrently from coroutines.
coset n 0
coincr n # $result = 0, n is now 1
coincr n 5 # $result = 1, n is now 6
0 Incremented. >0 Bad usage.
colist back to top ↑list coroutines and their status
colist [/active] [/completed] [/all]
Prints the tracked coroutines with their id and status (running, suspended, or completed). Filter with /active or /completed; /all (the default) shows both. Completed coroutines stay tracked until coclean removes them.
colist
colist /active
0 Always.
complete back to top ↑define tab completion rules
complete COMMAND PATTERN
complete COMMAND TYPE
Defines custom tab completion rules for commands. When you press Tab after a command, the shell uses these rules to suggest completions.
COMMAND Command to define completion for.
PATTERN Glob pattern for completions.
TYPE Completion type:
f Files (default)
d Directories only
c Commands
e Environment variables
a Aliases
v Variables
complete cd d
Complete cd with directories only.
complete type f
Complete type with files.
complete kill p
Complete kill with process IDs.
complete set v
Complete set with variable names.
complete source "*.csh"
Complete source with .csh files.
complete git "(add|commit|push|pull|status)"
Complete git with subcommands.
0 Success 1 Invalid pattern
Tab Completion: When you type a command and press Tab, the shell: 1. Checks for 'complete' rules for that command 2. Uses the rule to filter/suggest completions for the current token 3. Inserts the next match inline when there is a single match (or a shared prefix) 4. Displays a list of matches when multiple results exist 5. Falls back to default (file) completion if no rule
Interactive Behavior: - Tab completes the current word at the cursor (end-of-line) - If multiple matches exist, the shell prints them and redraws the prompt - Completion types support files, directories, commands, aliases, variables, and environment variables
Default Behavior: Without custom rules, Tab completes filenames.
Multiple Arguments: Completion rules can vary by argument position: complete command (dir file file)
Listing Rules: Use 'complete' without arguments to list all defined completions.
copy back to top ↑copy files
copy SOURCE DESTINATION
copy SOURCE... DIRECTORY
Aliases: cp
Copies one or more files to a destination. If the destination is a directory, files are copied into that directory preserving their original names. If copying a single file to a non-directory destination, the file is copied with the new name.
The copy command uses the Windows CopyFile API, which preserves file attributes and handles large files efficiently.
SOURCE The file(s) to copy. Wildcards (* and ?) are supported.
DESTINATION The target file or directory.
/y Suppress confirmation prompt when overwriting.
/v Verify that new files are written correctly.
copy file.txt backup.txt
Copy file.txt to backup.txt in the same directory.
copy document.docx D:\Backup\
Copy document.docx to the D:\Backup directory.
copy *.txt TextFiles\
Copy all .txt files to the TextFiles subdirectory.
copy "My File.doc" "My Backup.doc"
Copy a file with spaces in the name.
copy src\*.cpp backup\src\
Copy all C++ source files to a backup location.
0 Success - all files copied 1 Source file not found 2 Destination access denied or disk full 3 Syntax error
Overwriting: If the destination file already exists, copy will overwrite it without prompting (use /y to explicitly suppress any prompts).
Large Files: The copy command handles files of any size, including files larger than 4GB.
Network Paths: UNC paths (\\server\share\file) are fully supported.
Preserving Attributes: File attributes (read-only, hidden, system, archive) are preserved during the copy operation.
coresult back to top ↑get the result of a completed coroutine
coresult <coid>
Reads the return value published by a finished coroutine (the value it passed to retproc / return) and stores it in $result. Wait for the coroutine first with cowait if it may still be running.
corunproc compute 42
cowait $coid
coresult $coid
echo $result
0 Result retrieved. >0 Unknown coroutine id, or it has not completed.
coresume back to top ↑resume a suspended coroutine
coresume <coid>
Resumes a coroutine previously paused with cosuspend, letting it continue from where it yielded.
cosuspend $coid
coresume $coid
0 Resume requested. >0 Unknown coroutine id, or it was not suspended.
corunproc back to top ↑start a procedure as a concurrent coroutine
corunproc <procedure> [arg ...]
Starts a named proc running as a coroutine on its own cooperative task, returning immediately. The new coroutine's id is published in $coid; use it with cowait, coresult, cosuspend, coresume, and cocancel. Each coroutine gets its own variable scope; use coget / coset / coincr / codecr / cocas for thread-safe shared state, and the mutex / semaphore / event / barrier / channel primitives to coordinate.
corunproc worker 1 2 3
set id = $coid
cowait $id
coresult $id
0 Coroutine started. >0 No such procedure, or bad arguments.
cowait, coresult, cocancel, cosuspend, coresume, colist, wait
coset back to top ↑set a thread-safe atomic variable
coset <name> <value>
Stores value under name in cshw's atomic-variable table -- a thread-safe key/value store shared across coroutines and worker threads, SEPARATE from ordinary shell variables set with `set`. Read it back with coget, or use coincr / codecr / cocas for atomic numeric updates.
coset counter 0
coset owner ""
0 Stored. >0 Bad usage.
cosuspend back to top ↑suspend a running coroutine
cosuspend <coid>
Pauses a running coroutine at its next cooperative checkpoint. Resume it later with coresume. Suspending does not lose the coroutine's state or result.
cosuspend $coid
coresume $coid
0 Suspend requested. >0 Unknown coroutine id.
cowait back to top ↑wait for coroutine(s) to complete
cowait /all
cowait /any [/timeout:ms]
cowait [/timeout:ms] <coid> [coid ...]
wait
Blocks until coroutines finish. You must say which: /all waits for every running coroutine, /any returns as soon as one finishes (and sets $coid to it), or list explicit coroutine ids. With none of these, cowait is a usage error. /timeout:ms bounds the wait and reports a timeout if it elapses first. `wait` is a convenience alias equivalent to `cowait /all`.
/all Wait for all running coroutines.
/any Return when any one finishes; sets $coid to it.
/timeout:ms Give up after ms milliseconds (sets a timeout status).
corunproc a ; corunproc b
wait # == cowait /all
cowait /any /timeout:5000
cowait $id1 $id2
0 The awaited coroutine(s) completed. >0 Timed out, bad coroutine id, or no /all|/any|ids given.
cp back to top ↑copy files (alias for copy)
cp [-r | -R | --recursive] <source> <dest>
`cp` is identical to `copy`. See `man copy` for full documentation, options, and examples.
createwindow back to top ↑create a script-owned window on the UI thread
createwindow [<class>] [<title>] [/style:a,b,...] [/exstyle:a,b,...]
[/pos:x,y] [/size:w,h] [/parent:<hwnd>] [/id:<n>]
Creates a Win32 window on the CSHW UI thread and returns its HWND in $result (hex), plus a monotonic per-window cookie in $result_cookie that scripts can use to guard against the HWND-reuse window.
The window's whitelisted messages (WM_COMMAND, WM_NOTIFY, WM_TIMER, WM_LBUTTONDOWN/UP, WM_KEYDOWN, WM_SIZE, WM_CLOSE, WM_DESTROY) are routed back to bound script procs via `bindevent`.
<class> Window class. Default: CSHWScriptWindowClass (the built-in
generic script window). Plugin-registered classes are
also accepted by name.
<title> Window text. Default: empty.
/style:.. Comma-separated WS_* flags. Accepts symbolic names
(overlapped, visible, sysmenu, thickframe, tabstop,
child, popup, ...) and hex/decimal literals.
Default: WS_OVERLAPPEDWINDOW|WS_VISIBLE for top-levels,
WS_CHILD|WS_VISIBLE when /parent is given.
/exstyle:.. WS_EX_* flags (topmost, toolwindow, clientedge, ...).
Same comma-list syntax.
/pos:x,y Top-left position. Default: CW_USEDEFAULT.
/size:w,h Window size. Default: CW_USEDEFAULT.
/parent:<hwnd>
Parent HWND for child windows.
/id:<n> HMENU / child-id slot.
createwindow "" "My window" /size:400,300
set w = $result
# Add a child button:
addcontrol button $w "&OK" /pos:10,10 /size:80,25 /id:100
# React to its click:
proc on_ok
echo "ok clicked, ctlId=$1 code=$2"
endproc
bindevent $w command 100 on_ok
0 Success; $result is the HWND in hex, $result_cookie the cookie. 1 UI thread unavailable, unknown class, or bad style/pos/size.
The built-in CSHWScriptWindowClass has its dispatcher wired directly into its WndProc. For any OTHER class (plugin class, system control, foreign HWND), CSHW installs a SetWindowSubclass shim on top so the window is bindable-by-default.
addcontrol, bindevent, unbindevent, sendmessage, postmessage
crond back to top ↑cron daemon control
crond start
crond stop
crond status
crond restart
Controls the cron daemon that executes scheduled jobs defined in crontab. The daemon runs in the background, checking every minute for jobs to run.
start Start the cron daemon.
stop Stop the cron daemon.
status Show daemon status.
restart Stop then start the daemon.
crond start
Start the cron daemon.
crond status
Check if daemon is running.
crond stop
Stop the daemon.
crond restart
Restart after crontab changes.
0 Success 1 Daemon already running/stopped 2 Error starting/stopping
Background Process: crond runs as a background thread within CSHW. It continues running as long as the shell is open.
Auto-Start: To have crond start automatically, add 'crond start' to your shell startup script.
Job Execution: Jobs run in separate processes. Their output goes to a log file or is discarded depending on configuration.
Missed Jobs: If crond is not running when a job is scheduled, that execution is missed. crond does not run missed jobs.
Windows Task Scheduler: For persistent scheduled tasks that survive logoff/reboot, consider using Windows Task Scheduler instead: schtasks /create ...
crontab back to top ↑manage scheduled cron jobs
crontab -l
crontab -e
crontab -r
crontab FILE
Manages the cron job schedule for the current user. Cron jobs are commands that run automatically at specified times. CSHW provides a UNIX-compatible cron implementation on Windows.
-l, --list List current cron jobs.
-e, --edit Edit crontab (opens in editor).
-r, --remove Remove all cron jobs.
FILE Install cron jobs from FILE.
crontab -l
List all scheduled jobs.
crontab -e
Edit cron schedule in text editor.
crontab jobs.txt
Install jobs from file.
crontab -r
Remove all scheduled jobs.
Crontab file format (5 time fields + command):
# minute hour day month weekday command
0 * * * * echo "Runs every hour"
30 9 * * 1-5 backup.bat
0 0 1 * * monthly_report.exe
*/15 * * * * check_status.bat
0 Success 1 Error reading/writing crontab 2 Syntax error in crontab
Time Field Format: Field Values Special ───── ────── ─────── Minute 0-59 * (any), */n (every n) Hour 0-23 , (list), - (range) Day 1-31 Month 1-12 Weekday 0-6 (0=Sun)
Special Characters: * Any value */n Every n units (*/15 = every 15) , List (1,3,5) - Range (1-5)
Examples: 0 * * * * Every hour at :00 */15 * * * * Every 15 minutes 0 9 * * 1-5 9 AM on weekdays 0 0 1 * * Midnight on 1st of month 30 4 * * 0 4:30 AM on Sundays
Cron Daemon: Jobs only run if crond is running. Start with 'crond start'.
Storage: Crontab is stored in %APPDATA%\cshw\crontab.
cut back to top ↑remove sections from each line
cut -d DELIM -f FIELDS [FILE]
cut -c CHARS [FILE]
command | cut [options]
Extracts selected portions of each line from files or standard input. Useful for processing delimited data like CSV files or extracting specific columns from command output.
FILE File to process (default: stdin).
-d DELIM Use DELIM as field delimiter (default: tab).
-f FIELDS Select fields (columns). Examples:
-f 1 First field
-f 1,3 Fields 1 and 3
-f 1-3 Fields 1 through 3
-f 2- Field 2 to end
-c CHARS Select characters by position.
-c 1-10 Characters 1-10
-c 5 Character 5 only
-s Suppress lines without delimiters.
cut -d, -f1 data.csv
Extract first column from CSV file.
cut -d, -f1,3,5 data.csv
Extract columns 1, 3, and 5.
cut -d: -f1 /etc/passwd
Extract usernames (UNIX password file format).
echo "hello world" | cut -c1-5
Extract "hello".
processlist | cut -c1-40
Truncate process list output.
dir /b | cut -d. -f1
Extract filenames without extensions.
0 Success 1 Error
Delimiters: Common delimiters: - Comma: -d, - Tab: -d$'\t' (or default) - Colon: -d: - Space: -d' '
Field vs Character: - Use -f for delimited data (CSV, TSV) - Use -c for fixed-width data
One Delimiter Only: cut uses a single character as delimiter. For multi-character delimiters or complex parsing, consider using grep or scripting.
date back to top ↑display or format the current date and time
date [options]
date +FORMAT
Displays the current date and time. By default, shows the local date and time in a readable format. Various options control the output format.
-u, --utc Display time in UTC (Coordinated Universal Time)
-I, --iso Display in ISO 8601 format (YYYY-MM-DDTHH:MM:SS)
-R, --rfc Display in RFC 2822 format (for email headers)
+FORMAT Custom format string (see FORMAT SPECIFIERS)
%Y Four-digit year (e.g., 2024)
%m Month as two digits (01-12)
%d Day of month as two digits (01-31)
%H Hour in 24-hour format (00-23)
%M Minute (00-59)
%S Second (00-59)
%j Day of year (001-366)
%w Day of week (0-6, Sunday=0)
%W Week number of year (00-53)
%a Abbreviated weekday name (Sun, Mon, ...)
%A Full weekday name (Sunday, Monday, ...)
%b Abbreviated month name (Jan, Feb, ...)
%B Full month name (January, February, ...)
%p AM or PM
%Z Timezone name
%% Literal percent sign
date
Wed Jan 08 14:30:45 2025
date -u
Wed Jan 08 19:30:45 2025 UTC
date -I
2025-01-08T14:30:45
date -R
Wed, 08 Jan 2025 14:30:45 -0500
date +%Y-%m-%d
2025-01-08
date "+%H:%M:%S"
14:30:45
date "+Today is %A, %B %d"
Today is Wednesday, January 08
Unlike Unix date, this command cannot set the system date/time. Use Windows 'control timedate.cpl' to change the system time.
dc back to top ↑reverse-Polish arbitrary-precision calculator
dc interactive REPL
dc "COMMANDS" run commands from argv
dc -e "CMDS" [-e "CMDS"...] inline (repeatable)
dc -f FILE [-f FILE...] script from file (repeatable)
dc -i force REPL even with redirected stdin
dc is bc's reverse-Polish sibling. Numbers push to a value stack; single-character commands operate on the top. Same arbitrary-precision math backend as bc (Gavin Howard's BCL); completely different surface.
dc came first historically (1970, PDP-7); bc was originally a preprocessor that translated infix syntax into dc commands. Today they're separate languages.
+ - * / % pop two; push result
^ power
v sqrt (pops one)
_N negative literal prefix (e.g. _5 pushes -5)
c clear stack
d duplicate top
r swap top two
z push current stack depth
p print top with newline (does NOT pop)
n print top with no newline (POPS)
f print whole stack top-down
Single-character register names. Numeric and macro values stored
separately.
sR pop top and store into register R
lR push register R's value (default 0 if unset);
if R holds a macro, push it onto the macro stash
[BODY] push macro string
x pop a macro and execute it
<R >R =R pop two values; execute R as a macro if first<second
(i.e. earlier-pushed < later-pushed) / first>second
/ first==second. Comparison semantics follow POSIX
and Gavin Howard.
!<R !>R !=R same with the condition negated
.SCALE / BASE
k pop value N, set scale to N
K push current scale
i pop value N, set ibase to N
I push current ibase
o pop value N, set obase to N
O push current obase
q end the script
Q pop a count, end script
dc "1 2 +p" -> 3
dc "20k 1 3/p" -> .33333333333333333333
dc "20k 2vp" -> 1.41421356237309504880 (sqrt 2)
dc "_5 3+p" -> -2
dc "2o 10p" -> 1010 (binary output)
dc "16o 255p" -> FF (hex output)
dc "5sn lnln*p" -> 25 (square via register)
dc "[1+]sa 5 lax p" -> 6 (macro: add one)
dc "[d 1- d 1>f *]sf 5 lfx p" -> 120 (factorial via recursion)
With no inline source and a TTY stdin, dc enters an interactive REPL
showing `dc> ` between lines. Each typed line is executed atomically.
Type `q` to return to cshw.
.SEE ALSO
bc(1) the infix sibling
Implementation: BCL arithmetic + a cshw-written stack VM. Many extended dc commands from GNU / OpenBSD dc are not implemented in this release (~ R Z X ; : S L P |); they may land in a future cshw version if demand arises.
declare back to top ↑declare a variable with optional type / scope flags
declare [-r] [-l] [-a] [-A] <name> [= <value>]
Declares one variable, optionally marking it read-only (-r), local to the current proc (-l), an indexed array (-a), or an associative array (-A). Without flags, behaves like `set`.
The flags can be combined (e.g., `declare -lr CONST = 42` declares a local read-only constant inside a proc).
-r Mark the variable read-only (same as `readonly`).
-l Declare in the local proc scope (same as `local`).
-a Declare as an indexed array.
-A Declare as an associative array (hash).
<name> Variable name.
<value> Optional initial value.
declare -r MAX = 100
# Read-only global.
declare -lr loop_count = 0
# Read-only local (only meaningful inside a proc).
declare -a colors = (red green blue)
# Declare and fill in one line. Subscripts are 1-BASED:
# $colors[1] is "red".
declare -a more
set more[1] = "red"
set more[2] = "green"
# An empty array, then elements by index. `set more[0]` is a
# syntax error, not element 1 -- counting starts at 1.
declare -A users
hash set users alice admin
hash set users bob user
echo $users[alice]
# Hash entries are written with `hash set` and read with
# $name[key]. There is no `set users{alice}` form: it parses,
# does nothing, and returns 0.
0 Declaration succeeded. 1 Bad flag combination, syntax error, or read-only violation.
-a and -A differ only in case and ask for different containers, so giving both is refused rather than one of them quietly winning.
`declare` is the unified form for the related single-purpose commands: declare -r ... <=> readonly ... declare -l ... <=> local ... declare -a ... <=> array <name> declare -A ... <=> hash <name>
The single-purpose commands remain available; pick whichever reads more naturally in your script.
The flags used to do nothing. They are leading options, so the switch extractor consumed them before the command ran: `declare -a colors = (red green blue)` was byte-identical to the same line without the -a, a plain string with $#colors == 1. It hid well, because `foreach c ($colors)` still iterated three times -- foreach splits the string itself -- and `declare -A cfg` looked right whenever a `hash set` followed, since that creates the hash on its own.
del back to top ↑delete files
del <file> [<file> ...]
del /secure <file> [<file> ...]
del /recycle <file> [<file> ...]
Deletes one or more files. 'del' and 'rm' are aliases for the same handler; see rm(1) for the full description.
By default del permanently deletes the named files. Use /recycle to send them to the Recycle Bin (recoverable), or /secure to overwrite the file contents with zeros before deletion.
cshw accepts both Windows-style and Unix-style switch spellings. See rm(1) and rmdir(1) for the full set.
<file> File(s) to delete.
/secure, --secure
Overwrite the file contents with zeros before
deletion. Mutually exclusive with /recycle.
/recycle, --recycle
Send to the Recycle Bin. Fails (rather than silently
permanent-deleting) when the bin is unavailable; see
NOTES on rmdir(1).
del temp.txt
Permanently delete temp.txt.
del /recycle scratch.bin
Send scratch.bin to the Recycle Bin.
del /secure passwords.txt
Zero out and then delete.
df back to top ↑display disk free space
df
df [DRIVE]
df [options]
Reports file system disk space usage. Shows total, used, and available space on mounted drives.
DRIVE Show info for specific drive (e.g., C:).
-h, --human-readable
Print sizes in human readable format (KB, MB, GB).
-a, --all Accepted for compatibility. Network and removable
drives are listed either way; only drives with no
media, such as an empty optical drive, are omitted.
df
Show disk usage for all local drives.
df C:
Show disk usage for C: drive only.
df -h
Human-readable format (1K, 234M, 2G).
df .
Show the filesystem holding the current directory.
df C:\Users
Show the filesystem holding a path, which may be a mount point
rather than the drive letter it starts with.
0 Success 1 Error (invalid drive)
Output Columns: - Filesystem: Drive letter or mount point - Size: Total capacity - Used: Space in use - Avail: Space available - Use%: Percentage used - Mounted on: Drive description
Windows Drives: Shows fixed, removable and network drive letters. A drive with no media in it is skipped.
Operands are resolved, not sliced: `df C:` and `df C:\Users\you\project` both report the volume that actually holds the path, so a mounted folder reports its own volume rather than the letter its path happens to start with. The operand was ignored entirely before -- every form of df printed every drive.
diff back to top ↑compare files line by line
diff FILE1 FILE2
diff [options] FILE1 FILE2
Compares two files line by line and displays the differences. Output shows which lines need to be added, removed, or changed to transform FILE1 into FILE2.
FILE1 First file to compare.
FILE2 Second file to compare.
-u, --unified Output in unified diff format (shows context).
-c, --context Output in context diff format.
-i, --ignore-case
Ignore case differences.
-w, --ignore-whitespace
Ignore all whitespace.
-b Ignore changes in amount of whitespace.
-B Ignore blank lines.
-q, --brief Report only whether files differ.
diff old.txt new.txt
Compare two files and show differences.
diff -u original.cpp modified.cpp
Unified diff format (commonly used for patches).
diff -i file1.txt file2.txt
Case-insensitive comparison.
diff -q dir1/file dir2/file
Quick check if files differ.
diff -w config.old config.new
Ignore whitespace differences.
0 Files are identical 1 Files differ 2 Error (file not found, etc.)
Output Format: Default output uses traditional diff format: - Lines with < are from FILE1 - Lines with > are from FILE2 - Numbers indicate line positions
Unified Format (-u): - Lines with - are removed - Lines with + are added - Context lines are shown with space prefix
Use Cases: - Comparing code versions - Checking configuration changes - Creating patches
Binary Files: diff is designed for text files. Binary files will be reported as different but content won't be meaningfully shown.
dir back to top ↑display directory contents
dir [path] [options]
dir [path] [/switches]
Displays a list of files and subdirectories in a directory. Similar to the Windows DIR command but with additional formatting options and UNIX-style switch support.
By default, dir displays filenames, sizes, dates, and attributes. The output can be customized using various switches to show different information, sort results, filter by attributes, and control formatting.
path Directory or file pattern to list (default: current directory)
Supports wildcards: * (any characters) and ? (single character)
Attribute filters:
Hidden and system files are OMITTED unless asked for, as in cmd.exe.
Without that, `dir` in a home directory buries the answer under
NTUSER.DAT, ntuser.dat.LOG1, Cookies, NetHood and a dozen more.
/a Show all files including hidden and system
/ah Show only hidden files
/as Show only system files
/ar Show only read-only files
/aa Show only files with archive attribute
/ad Show only directories
/a-h Exclude hidden files
/a-s Exclude system files
/a-d Exclude directories (files only)
Sorting options:
/o Sort by name (ascending)
/o- Sort by name (descending)
/on Sort by name
/os Sort by size (smallest first)
/o-s Sort by size (largest first)
/oe Sort by extension
/od Sort by date/time (oldest first)
/o-d Sort by date/time (newest first)
/og Group directories first
Display options:
/b Bare format (names only, no header/footer)
/w Wide format (multiple columns)
/p Pause after each screenful
/l Use lowercase for filenames
/n Use long list format with new format
/q Show file owner
/r Include alternate data streams
/s Recurse into subdirectories
/x Show short (8.3) filenames
Time display:
/tc Show creation time
/ta Show last access time
/tw Show last write time (default)
Format options:
/4 Use 4-digit years in dates
/24 Use 24-hour time format
/-c Disable thousand separators in sizes
/attr Show file attributes column
Banner and summary:
Both are ON by default, matching cmd.exe. Turn them off for the
session with a setting, or for one listing with a switch:
set nodirbanner drop the " Directory of C:\path" line
set nodirsummary drop the "N File(s) ... bytes free" block
unset nodirbanner put it back
/banner /summary on, for this invocation
/-banner /-summary off, for this invocation
/header and /footer are accepted as aliases, because that is what a
cmd user will reach for first. The names above are the documented
ones: "header" is ambiguous in a listing -- a table can have column
headers -- while a banner cannot be misread, and "summary" is
Microsoft's own word for the bottom block. cmd's own /B help reads
"no heading information or summary".
The settings are spelled negatively because ON is the default, and
csh already names a switch you disable that way -- noclobber,
noglob, nonomatch.
A switch beats the setting in both directions, so a session with
`set nodirbanner` can still ask for the banner once with /banner.
/b (bare) suppresses both regardless, as it always has.
Nothing matched:
When no entry survives the pattern and the attribute filter, dir
prints "File Not Found" and returns 1 -- cmd's wording and cmd's
behaviour. An empty listing at status 0 is indistinguishable from an
empty directory, so `dir /a:h` with no hidden files, `dir *.zzz` and
`dir` in an empty folder used to be the same silent answer.
/b stays silent as it always has, but still returns 1.
dir
List contents of current directory.
dir C:\Users
List contents of C:\Users directory.
dir *.txt
List all text files in current directory.
dir /s *.exe
Recursively find all .exe files.
dir /ah
Show only hidden files.
dir /ad
Show only directories.
dir /o-s
Sort by size, largest first.
dir /o-d /s
Recursively list, newest files first.
dir /b > filelist.txt
Export bare file listing to a file.
dir /b /s *.cpp
Recursively list all .cpp files (paths only).
dir /q
Show file owners.
dir /attr
Show detailed file attributes.
dir /w
Wide format listing (multiple columns).
0 Success 1 Directory not found or access denied 2 Invalid argument
The dir command automatically formats file sizes with thousand separators for readability (e.g., 1,234,567 bytes). Use /-c to disable this.
For very large directories, consider using /p to pause between screens, or redirect output to a file or grep command.
File sizes are shown in bytes by default. Very large files (>1TB) may show approximate sizes.
dirname back to top ↑strip the last component from a path
dirname <path>
Print <path> with its last component removed, leaving the directory portion. Both forward slashes and backslashes are recognized as path separators, and trailing separators are ignored.
When <path> contains no directory component, dirname prints "." -- the current directory.
dirname does not touch the filesystem; it is a pure text operation on the path you give it.
dirname /usr/lib/file.txt
Prints: /usr/lib
dirname file.txt
Prints: .
dirname /usr/lib/
Prints: /usr (the trailing slash is ignored)
Zero on success. dirname with no path argument is a usage error.
dirs back to top ↑display directory stack
dirs
dirs [options]
Displays the directory stack maintained by pushd and popd commands. The stack shows directories in order from most recent (top) to oldest.
-c, --clear Clear the directory stack.
-l, --long Show full paths (don't abbreviate home directory).
-p Print one directory per line.
-v Print with index numbers.
dirs
Show directory stack.
pushd C:\Projects
pushd C:\Temp
pushd C:\Users
dirs
# C:\Users C:\Temp C:\Projects C:\OriginalDir
dirs -v
# 0 C:\Users
# 1 C:\Temp
# 2 C:\Projects
# 3 C:\OriginalDir
dirs -c
Clear the stack.
0 Success
$dirstack: The stack is also a variable. $dirstack[1] is the CURRENT directory and deeper indices are the pushd stack with the most recently pushed first, which is both the order `dirs` prints and the order tcsh uses. It moves with `cd` as well as with pushd and popd, and `dirs -c` leaves it holding just the current directory.
pushd libs echo "came from $dirstack[2]"
$dirstack was always empty before, so a script could read the text `dirs` prints but had no way to get at an entry.
Stack Order: - Index 0 is the current directory - Higher indexes are older entries - pushd adds to stack, popd removes
Empty Stack: If no directories have been pushed, dirs shows only the current directory.
Navigation: Use pushd/popd for efficient navigation between multiple working directories.
disown back to top ↑release a job without stopping the process
disown [%JOBID]
disown
Removes a job from this shell's job table without touching the process. The process keeps running; cshw simply stops tracking it.
After disowning, the job no longer appears in 'jobs', is not waited for by 'wait', and does not trigger the unfinished-jobs warning when the shell exits.
With no argument, releases the current job (%+).
%JOBID Job to release. Accepts %1, %%, %+, %-, %name, or a
bare job number.
longbuild.exe &
# [1] 24680
disown %1
# [1] 24680 released (still running)
jobs
# No jobs.
adopt 41288
disown %1
Adopted the wrong process; put it back the way it was.
0 Released 1 No such job, or the job is a coroutine
Coroutine jobs cannot be disowned. A coroutine is a thread inside cshw and cannot outlive the shell -- shutdown cancels it regardless -- so "forget about it but leave it running" is not something that can be honoured. Use 'cocancel' to stop one.
Disowning does not detach the process from the console it shares with cshw. A console program that is still writing will keep writing to your terminal.
dllimport back to top ↑load DLL for function calls
dllimport PATH
dllimport PATH ALIAS
Loads a Dynamic Link Library (DLL) into the shell process for later use with rundllproc. The DLL remains loaded until explicitly unloaded or the shell exits.
PATH Path to the DLL file.
ALIAS Optional short name to reference the DLL.
dllimport C:\MyApp\helper.dll
Load DLL by path.
dllimport C:\MyApp\helper.dll myhelper
Load DLL with alias "myhelper".
dllimport kernel32.dll
Load system DLL.
dllimport "C:\Program Files\App\plugin.dll" plugin
Load DLL with spaces in path.
# Then use with rundllproc:
rundllproc myhelper DoSomething
0 Success 1 DLL not found 2 Load failed (dependencies missing, wrong architecture) 3 Alias already in use
Dependencies: The DLL and all its dependencies must be available. Check with peinfo or Dependency Walker if loading fails.
Architecture: 32-bit DLLs can only be loaded by 32-bit CSHW. 64-bit DLLs can only be loaded by 64-bit CSHW.
Persistence: Loaded DLLs remain in memory until: - Explicitly unloaded with dllunload - Shell exits
Use Cases: - Calling custom DLL functions - Automation with COM objects - Extending shell functionality - Testing DLL code
Security: Only load DLLs you trust. Malicious DLLs can execute arbitrary code in the shell process.
dlllist back to top ↑list imported DLLs
dlllist
Lists all DLLs currently loaded via dllimport. Shows the alias (if any) and full path for each loaded DLL.
dlllist
# myhelper C:\MyApp\helper.dll
# plugin C:\Program Files\App\plugin.dll
# kernel32 C:\Windows\System32\kernel32.dll
dllimport C:\test.dll test
dlllist
# test C:\test.dll
0 Success (always)
Empty List: If no DLLs have been imported, dlllist shows nothing.
System DLLs: Only DLLs explicitly loaded with dllimport are shown, not DLLs loaded automatically by the shell or Windows.
Management: Use dlllist to see what's loaded before: - Calling rundllproc - Unloading with dllunload - Debugging DLL issues
dllunload back to top ↑unload a previously imported DLL
dllunload ALIAS
dllunload PATH
Unloads a DLL that was previously loaded with dllimport. Frees the DLL from memory and removes it from the import cache.
ALIAS Alias assigned during dllimport.
PATH Original path used in dllimport.
dllunload myhelper
Unload DLL by alias.
dllunload C:\MyApp\helper.dll
Unload DLL by path.
dlllist
# helper (C:\MyApp\helper.dll)
dllunload helper
dlllist
# (empty)
0 Success 1 DLL not found in cache
Reference Counting: If other code still holds references to the DLL, it may not be fully unloaded from memory until all references are released.
Cleanup: It's good practice to unload DLLs when done, but they're automatically cleaned up when the shell exits.
Error Handling: Unloading a DLL while code is executing from it can cause crashes. Ensure no operations are in progress.
du back to top ↑estimate file space usage
du [path]
du [options] [path]
Estimates and displays the disk space used by files and directories. Useful for finding large files or directories consuming disk space.
path Directory to analyze (default: current directory).
-h, --human-readable
Print sizes in human readable format (KB, MB, GB).
-s, --summarize Show only total for each argument.
-a, --all Show sizes for all files, not just directories.
-d N, --max-depth=N
Show totals for directories N levels deep.
du
Show disk usage for current directory tree.
du -h
Human-readable output.
du -s *
Summary of each item in current directory.
du -h -s C:\Users
Total size of Users directory.
du -d 1
Show only immediate subdirectories.
du -h -d 2 C:\Projects
Show projects with 2 levels of detail.
du -a | sort -n | tail -20
Find 20 largest items.
0 Success 1 Path not found 2 Access denied to some directories
Performance: du must traverse the entire directory tree, which can be slow for large directories or network drives.
Access Denied: Some directories may be inaccessible. du continues with accessible directories and reports errors for inaccessible ones.
Symbolic Links: Symbolic links are not followed by default to prevent counting the same files multiple times.
Finding Large Directories: du -h -d 1 | sort -h | tail -10
echo back to top ↑display text or variable values
echo [text...]
echo $variable
echo "text with $variable expansion"
Displays a line of text or the value of variables to standard output. The echo command performs variable expansion, substituting $variable references with their actual values.
echo is fundamental for shell scripts, debugging, and creating output. It supports both simple text display and complex variable interpolation.
text The text to display. Multiple arguments are separated
by spaces in the output.
Variables are expanded:
$name Expands to the value of shell variable 'name'
$? Expands to the last command's exit code
$: Expands to the current working directory
$$ Expands to the shell's process ID
echo Hello World
Displays: Hello World
echo $PATH
Displays the value of the PATH environment variable.
echo "Current directory: $:"
Shows current directory with label.
echo "Last exit code was $?"
Shows the previous command's exit code.
echo The answer is $answer
Variable expansion in unquoted text.
echo "Hello, $name! Welcome to $:"
Multiple variable expansions in one string.
echo
Outputs an empty line.
echo "Line 1" > file.txt
Redirect echo output to a file.
echo "Another line" >> file.txt
Append echo output to a file.
0 Success (always, unless I/O error)
$echo_style: Which of the two incompatible echoes this is, as in tcsh:
bsd -n suppresses the trailing newline; backslash escapes are
literal. This is the default and what cshw has always done.
sysv Backslash escapes are interpreted; -n is an ordinary word
and gets printed.
both Both.
none Neither.
Under sysv and both, these escapes are expanded: \a \b \e \f \n \r \t \v \ and \0nnn (up to three octal digits). \c stops output there and suppresses the newline. A backslash sequence echo does not recognize is left as written rather than having its backslash swallowed.
All four values used to behave as bsd, so a ported script that set sysv to get \t and \n interpreted printed the backslashes instead, at status 0.
Variable Expansion: Variables prefixed with $ are automatically expanded. To display a literal dollar sign, you can escape it or use single quotes in scripts.
Unlike UNIX echo, CSHW's echo does not support -n (no newline) or -e (escape sequences) flags. Each echo command outputs a newline.
Empty Variables: If a variable is not defined, $variable expands to an empty string without generating an error.
Quoting: Use double quotes to preserve spaces and ensure proper variable expansion. Without quotes, multiple spaces between words may collapse to single spaces.
enable back to top ↑Enable or disable a built-in (bash's spelling of shadow).
endsplash back to top ↑dismiss the modeless splash dialog
endsplash
Dismisses the modeless splash dialog put up by `splash`. Safe to call when no splash is showing -- it's a clean no-op.
splash
# ... long-running work ...
endsplash
0 Always (success even when no splash is showing).
env back to top ↑display or modify environment
env
env NAME=VALUE... COMMAND
env -u NAME COMMAND
Displays all environment variables or runs a command with a modified environment. Useful for temporarily changing environment variables for a single command without affecting the shell's environment.
Without arguments, displays all environment variables.
NAME=VALUE Set variable for the command.
-u NAME Unset variable for the command.
-i Start with empty environment.
COMMAND Command to run with modified environment.
env
Display all environment variables.
env | grep PATH
Show PATH-related variables.
env DEBUG=1 myprogram.exe
Run program with DEBUG=1 set.
env -u PROXY myprogram.exe
Run program with PROXY unset.
env PATH="C:\Tools;%PATH%" tool.exe
Run with modified PATH.
env -i TERM=xterm program.exe
Run with minimal environment.
0 Success (or command's exit code) 1 Error
Temporary Changes: env changes don't affect the shell. After the command completes, the environment is unchanged: env DEBUG=1 program.exe # DEBUG is NOT set here
Display Format: Variables are shown as NAME=VALUE, one per line.
Sorting: Output is typically sorted alphabetically by name.
Comparison: - env: Display or temporarily modify environment - setenv: Permanently set in current shell - printenv: Display only (no modification)
eval back to top ↑concatenate arguments and run the result as a command
eval [argument ...]
Join the arguments together with single spaces and run the resulting string as a command in the current shell. The arguments have already been through one round of the shell's tokenizing and expansion; running the joined string back through the shell triggers a second round.
That second round is the whole point of eval. Use it when: - a command line has been built up inside a variable - variable or command-substitution expansion must be deferred until the moment eval runs, rather than when the line was first parsed
eval runs in the current shell, so any variable assignments, cd, or other state changes made by the evaluated command persist.
set cmd = "echo hello"
eval $cmd
Runs: echo hello
eval 'echo $HOME'
The single quotes stop $HOME from expanding when the line is
first read; eval expands it on the second pass.
set assign = "set count = 5"
eval $assign
$count is now 5 in the current shell.
The exit status is that of the evaluated command. eval with no arguments is a successful no-op.
Quoting from the first parse is intentionally not preserved -- eval's contract is to re-parse. `eval echo "a b"` runs `echo a b`, passing two arguments.
event back to top ↑manual/auto-reset event signal
event <name> create [/manual]
event <name> signal
event <name> reset
event <name> wait
event <name> trywait [/timeout:ms]
event <name> pulse
event <name> destroy
A named Win32-style event for signaling between coroutines and threads. Auto-reset by default (one waiter is released per signal, then the event resets); with /manual it stays signaled until reset, releasing all waiters. Create it before signal/reset/wait/pulse -- operating on an unknown name is an error.
create [/manual] Create the event (auto-reset unless /manual).
wait Block until signaled. FATAL on timeout -- see below.
trywait [/timeout:ms]
Poll (or wait up to ms); $? = 0 signaled, 1 not.
Never fatal.
signal Set to the signaled state.
reset Return to the non-signaled state.
wait [/timeout:ms] Block until signaled; $? = 0 signaled, 1 timeout.
pulse Signal, releasing current waiters, then reset.
destroy Remove the event.
ON FAILURE
`wait` is FATAL: "wait" means do not continue until this has happened, so a
timeout -- meaning it did NOT happen -- stops the script rather than running
code written on the assumption that it did. `trywait [/timeout:ms]` is the
polling form: it reports through $? and continues.
event ready create /manual
corunproc worker # worker does: event ready wait
event ready signal
0 Operation succeeded (wait: signaled). >0 Wait timeout, unknown name, or bad usage.
example back to top ↑Show or run a bundled example script.
exec back to top ↑replace shell with command
exec COMMAND [ARGS...]
Replaces the current shell process with the specified command. The command runs in place of the shell - when the command exits, there is no shell to return to.
COMMAND Command to execute.
ARGS Arguments for the command.
exec notepad
Replace shell with Notepad.
exec cmd
Replace shell with Windows cmd.exe.
exec /usr/bin/bash
Replace with another shell.
exec python script.py
Run Python script, exit when done.
Does not return (shell is replaced).
No Return: exec does not return. The shell process is completely replaced by the new command. When that command exits, the window closes.
Use Cases: - Final command in a script - Switching to another shell - Wrapper scripts that launch another program - Reducing process overhead (no extra shell process)
Comparison with start: - exec: Replaces shell, no return - start: New window, shell continues
Resource Efficiency: exec is slightly more efficient than starting a child process because it doesn't keep the shell running.
Scripts: In scripts, commands after exec never run: exec myprogram echo "Never executed"
exit back to top ↑exit the shell
exit [CODE]
Terminates the shell session. An optional exit code can be specified to return to the parent process or operating system.
In scripts, exit terminates script execution and returns the specified code.
CODE Integer exit code (default: 0).
Convention:
0 = success
non-zero = error/failure
exit
Exit shell with code 0 (success).
exit 0
Explicitly exit with success.
exit 1
Exit with error code 1.
# In a script:
if ($result != "ok")
exit 1
endif
Exit script on error condition.
Returns the specified CODE or 0 if not specified.
Running Jobs: If background jobs are running, exit may warn you. Use 'jobs' to check for running jobs before exiting.
Scripts: In scripts, exit immediately terminates execution. No further commands are run.
Return vs Exit: In procedures, use 'return' instead of 'exit' to return control to the caller without terminating the shell.
false back to top ↑return failure (documented with true)
false
Sets $status to 1 (failure). Documented alongside `true` and `nop` on a single page -- see `man true` for full details.
fetch back to top ↑transfer data from a URL (HTTP/HTTPS/FTP client)
fetch [options] URL
fetch /o:FILE URL
fetch /I URL
Transfers data from a URL to stdout (or a file), similar to curl or wget.
By default HTTP and HTTPS go through WinHTTP, which negotiates HTTP/2 or HTTP/1.1 with the server. To pin the protocol, use /http2 or /http3: these select cshw's own native client, which GUARANTEES the protocol rather than negotiating it -- nghttp2 over SChannel TLS for HTTP/2, and msquic + nghttp3 (QUIC/UDP) for HTTP/3. The protocol actually used is reported with /I or /v and is set in $result. ftp:// URLs are also supported (via WinINet).
Switches accept either /name or -name / --name form.
/o:FILE, /output:FILE
Write the response body to FILE instead of stdout.
/O Save to a file named after the URL's last path segment (e.g.
fetch /O https://host/file.zip writes file.zip). Errors if the
URL has no filename.
/c, /continue Resume a partial download (requires /o or /O). Sends a Range
request from the current file size and appends the rest; if the
file is already complete, nothing is downloaded.
/I, /head Print only the response headers (and the protocol used), no body.
/v, /verbose Verbose: print headers + protocol, then the body.
/s, /silent, /q, /quiet
Suppress fetch's own error messages.
/X:METHOD, /request:METHOD
HTTP method (GET, POST, PUT, DELETE, ...). Default GET.
/d:DATA, /data:DATA
Send DATA as the request body (use with /X:POST). Sent as
application/x-www-form-urlencoded.
/http2, /2 Force HTTP/2 using the native nghttp2 client over SChannel TLS
(ALPN "h2"). https only. Unlike the WinHTTP default, the
connection IS HTTP/2 or it fails -- it never silently downgrades.
/http3, /3 Force HTTP/3 using the native msquic + nghttp3 client (QUIC over
UDP, ALPN "h3"). https only. The server must offer HTTP/3 on the
URL's port; there is no Alt-Svc-based upgrade from TCP.
/k, /insecure, /no-check-certificate
Skip TLS certificate validation. For self-signed / local test
servers only -- never against real services (the certificate is
the only thing preventing a man-in-the-middle).
$result is set to the protocol used: "HTTP/1.1", "HTTP/2", or "HTTP/3" (with /http2 or /http3 this is the forced protocol; otherwise it is what WinHTTP negotiated).
fetch https://example.com
Print the page to stdout.
fetch /o:page.html https://example.com
Save the response body to page.html.
fetch /O https://example.com/archive.zip
Save as archive.zip (filename taken from the URL).
fetch /c /O https://example.com/big.iso
Resume a partial big.iso download.
fetch /I https://example.com
Show response headers and the protocol used.
fetch /X:POST /d:"name=value" https://api.example.com/submit
POST a form body.
fetch /http2 /I https://example.com
Force HTTP/2 via the native client and show the headers.
fetch /http3 /I https://cloudflare.com
Force HTTP/3 (QUIC) via the native client.
fetch /k https://localhost:8443/
Fetch from a local server with a self-signed certificate.
The default (WinHTTP) path negotiates HTTP/2 or HTTP/1.1 and is best-effort -- WinHTTP's client-side HTTP/2 is not always selected even against an h2-capable server. When you need a specific protocol, use /http2 or /http3: those use cshw's native clients and guarantee it (nghttp2 for h2; msquic + nghttp3 for h3), the same libraries the cshw http.dll and quicsrv servers use. The native path requires nghttp2.dll / nghttp3.dll / msquic.dll beside cshw.exe; if they are absent only /http2 and /http3 are affected -- the default path still works.
0 Success >0 Error (bad URL, connection failure, HTTP/file error)
fg back to top ↑move job to foreground
fg [%JOBID]
Brings a background job to the foreground, making it the active process. If no job ID is specified, operates on the current job.
%JOBID Job number (from jobs command).
fg
Bring current job to foreground.
fg %1
Bring job 1 to foreground.
fg %2
Bring job 2 to foreground.
0 Success 1 No such job
Interaction: Once in foreground, you can interact with the process normally. Use Ctrl+Z to stop and background it again.
Wait for Completion: fg waits for the job to complete or be stopped before returning control to the shell.
file back to top ↑identify file type
file FILE
file FILE...
Determines file type by examining content, not just the extension. Uses "magic numbers" (byte patterns) to identify file formats.
FILE One or more files to identify.
-b, --brief Don't show filename in output.
-i, --mime Output MIME type instead of description.
-z Try to look inside compressed files.
file document.pdf
# document.pdf: PDF document, version 1.4
file image.png
# image.png: PNG image data, 800 x 600, 8-bit/color RGBA
file program.exe
# program.exe: PE32+ executable (GUI) x86-64
file unknown
# unknown: ASCII text
file mystery.dat
# mystery.dat: Zip archive data, at least v2.0 to extract
file -i document.pdf
# document.pdf: application/pdf
file *
Identify all files in directory.
0 Success 1 Error
Magic Numbers: Many file formats start with distinctive byte sequences: - PNG: 89 50 4E 47 0D 0A 1A 0A - PDF: 25 50 44 46 (% P D F) - ZIP: 50 4B 03 04 - EXE: 4D 5A (MZ) - JPEG: FF D8 FF
Extension Independence: file identifies by content, so renamed files are identified correctly: mv image.png image.txt file image.txt # Still identifies as PNG
Use Cases: - Verify file types before processing - Find misnamed files - Security analysis - Batch file organization
Unknown Files: For unrecognized formats, file reports basic type: - "data" for binary files - "ASCII text" or "UTF-8 text" for text
file-rename back to top ↑rename files with a Perl-style expression
file-rename [options] EXPRESSION FILE...
Identical to `prename`. Both names are registered because perl-rename ships under both in the wild -- Debian packages it as `prename` and `file-rename` -- so a script written against either runs unmodified.
See `man prename` for the expression forms, the options, and why --perl is opt-in.
fileblob back to top ↑encode a file into a one-line text blob
fileblob <file>
fileblob reads <file> and writes a single line of text -- a "blob" -- to standard output. The blob is the file's bytes base64-encoded behind a CSHWBLOB1 header that also records the original filename:
CSHWBLOB1:<original-name>:<base64-data>
Because the blob is plain text it can go wherever text can: captured into a shell variable, redirected to a .blob file, or pasted inline in a script -- a way to carry a binary asset (an icon, a small data file) as text. Decode it again with unfileblob.
set logo = `fileblob icon.png`
Hold a binary asset in a shell variable.
fileblob icon.png > icon.blob
Save the blob to a file for use later.
0 on success; non-zero if the file cannot be read.
find back to top ↑search for files in a directory tree
find [path] -name PATTERN [filters...]
find [path] [filters...]
find PATTERN [dir] [/s] [filters...]
Searches for files and directories matching a name pattern, optionally filtered by type, size, modification time and depth.
find accepts two operand orders, and tells them apart by whether the first operand is a directory that exists:
find . -name "*.txt" Unix order: a path, then filters.
Recursive, like every other find.
find "*.txt" . /s cshw's own order: the pattern first,
then the directory. NOT recursive
unless /s is given.
A lone directory operand is the Unix reading: `find src` lists everything under src. A lone pattern is cshw's: `find "*.log"` matches in the current directory only.
Every match prints on its own line, path included. Nothing matching is not an error; a search root that does not exist is.
path Directory to search from (default: current dir).
Its presence turns recursion on.
-name PATTERN Match PATTERN (supports * and ? wildcards).
Matching is case-insensitive on Windows.
-iname PATTERN Same thing. Windows filename comparison is already
case-insensitive, so -iname is a synonym here
rather than a separate mode.
-type TYPE Filter by type:
f Regular files only
d Directories only
-size [+|-]N Find files by size:
N Exactly N bytes
+N Greater than N bytes
-N Less than N bytes
Suffixes: c (bytes), k (KB), M (MB), G (GB)
-mtime [+|-]N Find by modification time (days):
N Modified exactly N days ago
+N Modified more than N days ago
-N Modified less than N days ago
-maxdepth N Descend at most N directory levels.
-mindepth N Ignore matches shallower than level N.
-delete Delete each match after printing it.
-print No-op. cshw's find always prints; -print is accepted
so GNU-style command lines do not have to be edited.
/s Recurse. Only needed in the pattern-first order --
a path operand implies it.
Anything else beginning with - or / is an error, not a silent
no-op: a filter find does not implement must never be mistaken for
one it honoured.
find . -name "*.txt"
Every .txt file under the current directory.
find C:\Users -name "*.doc"
Every .doc file under C:\Users.
find . -type f -name "*.log"
Only files (not directories) with a .log extension.
find . -type d
Only directories.
find . -size +10M
Files larger than 10 megabytes.
find . -mtime -7
Files modified in the last 7 days.
find . -maxdepth 2 -name "*.exe"
Search only 2 levels deep.
find src
Everything under src.
find "*.log"
Matches in the current directory only -- no recursion, because
no path operand was given.
find "*.tmp" . /s -mtime +30 -delete
The pattern-first order: month-old temp files, deleted.
0 The search ran (matches may or may not have been found).
1 The search root does not exist, or an unrecognized filter
was given.
Quote your patterns: find . -name "*.txt" Without the quotes the shell expands *.txt against the current directory before find ever sees it, and find searches for whatever that happened to produce.
Wildcards: * Matches any sequence of characters ? Matches any single character
Performance: On very large trees, use -maxdepth to bound the walk.
Combining with other commands: find . -name "*.log" | grep error find . -name "*.bak" | wc -l
fmt back to top ↑reflow paragraphs to a width
fmt [-w N] [FILE...]
Fills paragraphs so that lines are as full as they can be without exceeding a width. With no FILE, reads standard input.
fmt REFLOWS: it joins the lines of a paragraph back together and re-breaks them at word boundaries, so ragged text comes out evenly filled. A blank line separates paragraphs and is preserved, so structure survives.
-w N Fill to N columns. Default 72.
The historical form -N (e.g. -60) means the same thing.
fmt notes.txt
Reflow to the default 72 columns.
fmt -w 60 notes.txt
Narrower.
fmt -w 65 letter.txt | pr -h "Draft" | lp
Reflow, paginate, print.
0 Success 1 A named file could not be opened
fmt versus fold: fold -w 20 cuts each line at 20 columns; short lines stay short fmt -w 20 joins the paragraph up and refills every line
Given three short lines, fold leaves three short lines and fmt merges them into one full one. Use fmt for prose, fold when line boundaries carry meaning and must not move.
Word longer than the width: A word that cannot fit is placed on a line of its own and allowed to overrun, rather than being split. fold -s makes the opposite choice.
Where this differs from GNU fmt: cshw fills GREEDILY -- each line takes as many words as fit within the width. GNU's fmt instead aims at a goal width of roughly 93% of the maximum and chooses breaks that minimise raggedness across the whole paragraph, so its lines come out shorter and more even. Measured on the same input at -w 30, GNU produced lines of 25, 27, 23 and 12 columns; cshw produces 30, 30 and 28.
Both honour the width as a hard maximum, and neither splits words. If you need output identical to GNU's, pipe through GNU fmt; if you need lines filled to the width you asked for, this is what you want.
fold back to top ↑wrap long lines to a fixed width
fold [-w N] [-s] [FILE...]
Breaks each input line so that no output line is longer than a given width. With no FILE, reads standard input.
fold CUTS; it does not reflow. Every input line is broken independently, and short lines are left exactly as they are. When you want ragged text filled out into even paragraphs, that is fmt.
-w N Wrap at N columns. Default 80.
The historical form -N (e.g. -20) means the same thing.
-s Break at a space, so words are not split. If a single
word is longer than the width it is still broken -- it
has to go somewhere.
-b Accepted and ignored. Counts bytes rather than columns
in other implementations; cshw counts characters.
fold -w 40 notes.txt
Hard-break every line at 40 columns.
fold -s -w 40 notes.txt
Break at spaces instead, so words stay whole.
cat report.txt | fold -s -w 72 | lp
Wrap for a printer that cannot handle long lines.
0 Success 1 A named file could not be opened
fold versus fmt: fold -w 20 cuts each line at 20 columns, leaving short lines short fmt -w 20 joins the text back together and refills to 20 columns
Use fold when line boundaries matter and must not move, such as fixed-record data. Use fmt for prose.
ftpfetch back to top ↑FTP file transfer client
ftpfetch URL
ftpfetch [options] URL
Downloads files from FTP servers. Supports anonymous and authenticated FTP transfers.
URL FTP URL to download from.
Format: ftp://[user:pass@]host/path
-o FILE Output filename (default: derived from URL).
-u USER FTP username.
-p PASS FTP password.
-P PORT FTP port (default: 21).
-v, --verbose Show transfer progress.
--passive Use passive mode (default).
--active Use active mode.
ftpfetch ftp://ftp.example.com/pub/file.zip
Anonymous download.
ftpfetch -o download.zip ftp://ftp.example.com/file.zip
Download with specific output name.
ftpfetch -u myuser -p mypass ftp://ftp.example.com/private/data.txt
Authenticated download.
ftpfetch ftp://user:pass@ftp.example.com/file.txt
Credentials in URL.
ftpfetch -v ftp://ftp.example.com/large.iso
Verbose mode with progress.
0 Success 1 Connection error 2 Authentication failed 3 File not found 4 Transfer error
Anonymous FTP: Without credentials, ftpfetch uses anonymous login (typically "anonymous" with email as password).
Passive vs Active: - Passive mode (default): Works through firewalls - Active mode: May be blocked by firewalls
URL Format: ftp://ftp.example.com/pub/file.txt Anonymous ftp://user:pass@ftp.example.com/file Authenticated
Binary vs ASCII: ftpfetch uses binary mode by default, appropriate for most files.
Security: FTP transmits credentials in plain text. For secure transfers, consider SFTP or HTTPS instead.
Large Files: ftpfetch supports large files and shows progress in verbose mode.
genai back to top ↑interact with AI language models
genai register PROVIDER API_KEY [options]
genai list
genai remove NAME
genai default NAME
genai complete PROMPT
genai chat
genai analyze FILE
Interface to generative AI language models including OpenAI (GPT) and Anthropic (Claude). The genai command allows you to register AI providers, send prompts, have conversations, and analyze files using AI.
This is a powerful tool for code generation, text analysis, problem solving, and interactive AI assistance directly from the shell.
Subcommands:
register PROVIDER API_KEY [options]
Register a new AI provider.
PROVIDER: openai, anthropic
API_KEY: Your API key for the provider
Options:
--model MODEL Model to use (e.g., gpt-4, claude-3-opus)
--name NAME Custom name for this configuration
--default Set as default provider
list
Display all registered AI providers.
remove NAME
Remove a registered provider configuration.
default NAME
Set the default AI provider.
complete PROMPT
Send a prompt and get a completion response.
Also accepts piped input.
chat
Start an interactive chat session.
Type 'exit' or 'quit' to end.
analyze FILE
Send file contents to AI for analysis.
genai register openai sk-xxx123 --model gpt-4 --default
Register OpenAI with GPT-4 as the default.
genai register anthropic sk-ant-xxx --model claude-3-opus --name claude
Register Anthropic's Claude as 'claude'.
genai list
Show all registered AI providers.
genai default claude
Switch default to the 'claude' configuration.
genai complete "Write a Python hello world program"
Get an AI-generated response.
genai complete "Explain this code:" < script.py
Pipe file content with a prompt.
type error.log | genai complete "What caused this error?"
Analyze log file with AI.
genai chat
Start interactive conversation mode.
genai analyze main.cpp
Have AI analyze a source file.
echo "Translate to French: Hello" | genai complete
Use piped input as the prompt.
0 Success 1 Provider not found or not configured 2 API error (invalid key, rate limit, etc.) 3 Network error 4 Invalid arguments
OPENAI_API_KEY Default API key for OpenAI ANTHROPIC_API_KEY Default API key for Anthropic
%APPDATA%\cshw\genai.json Stored provider configurations
API Keys: Keep your API keys secure. They are stored in the configuration file. Consider using environment variables for sensitive keys.
Rate Limits: AI providers have rate limits. If you exceed them, you'll receive an error. Wait before retrying.
Costs: API calls may incur costs depending on your provider plan. Monitor your usage on the provider's dashboard.
Model Selection: Different models have different capabilities and costs: - gpt-4: Most capable OpenAI model, higher cost - gpt-3.5-turbo: Fast and economical - claude-3-opus: Most capable Anthropic model - claude-3-sonnet: Balanced performance/cost
Token Limits: Each model has maximum token limits. Very long prompts or files may be truncated or cause errors.
Interactive Chat: In chat mode, context is maintained within the session. The AI remembers previous messages in the conversation.
glob back to top ↑expand filename patterns
glob PATTERN
glob PATTERN...
Expands wildcard patterns into matching filenames. Useful for testing patterns before using them in commands, or in scripts that need explicit filename lists.
PATTERN Wildcard pattern to expand.
Wildcards:
* Match any characters (including none)
? Match exactly one character
[abc] Match any character in brackets
[a-z] Match character range
[!abc] Match any character NOT in brackets
glob *.txt
List all .txt files.
glob src/*.cpp
List C++ files in src directory.
glob [A-Z]*.doc
Files starting with uppercase letter.
glob ???.txt
Three-character names with .txt extension.
glob **/*.h
Recursively find header files.
glob file[0-9].dat
Match file0.dat through file9.dat.
glob *.[ch]
Match .c and .h files.
glob [!._]*
Files not starting with . or _
0 Matches found 1 No matches
No Matches: On a COMMAND LINE, a pattern that matches nothing is an error, as in csh: the shell reports "PATTERN: No match.", runs nothing, and sets the status to 1. That is what stops `rm *.tmp` from being handed a literal asterisk in a directory with no .tmp files.
set nonomatch pass the unmatched word through as typed instead set noglob turn filename substitution off altogether
An unterminated `[` is not a pattern at all -- `echo [` prints a bracket rather than reporting no match -- because a character class needs a closing `]` to be one. The target of an assignment is not a pattern either, so `set list[2] = x` addresses element 2 rather than looking for a file called list[2].
Escaping: To match literal wildcard characters, escape them: glob file\*.txt # Matches "file*.txt" literally
Hidden Files: By default, patterns don't match files starting with '.' Use .* to explicitly match hidden files.
Directory Patterns: glob can expand directories too: glob */ # All subdirectories
Recursive Patterns: Use **/ for recursive matching: glob **/*.log # All .log files in all subdirectories
Use in Scripts: set files=$(glob *.txt) foreach f ($files) echo "Processing $f" endforeach
grep back to top ↑search for patterns in files
grep [options] PATTERN [FILE...]
grep [options] PATTERN
Searches for PATTERN in each FILE or standard input. By default, grep prints the matching lines. PATTERN is a regular expression using PCRE2 (Perl Compatible Regular Expressions) syntax when available, falling back to std::wregex otherwise.
grep is one of the most powerful text-processing tools in CSHW, supporting both simple string searches and complex pattern matching with full regex capabilities including lookahead, lookbehind, and Unicode support.
When reading from standard input (piped data), grep processes each line and outputs those matching the pattern.
PATTERN The regular expression to search for.
FILE... One or more files to search. If omitted, reads stdin.
-i, --ignore-case
Perform case-insensitive matching.
-v, --invert-match
Invert the sense of matching - select non-matching lines.
-n, --line-number
Prefix each output line with its line number in the file.
-h, --no-filename
Suppress the prefixing of filenames on output when
searching multiple files.
-r, --recursive
Recursively search subdirectories.
-l, --files-with-matches
Only print filenames containing matches (not the lines).
-c, --count
Only print a count of matching lines per file.
-o, --only-matching
Print only the part of each line that matched, one match
per line, instead of the whole line. Use it to pull a
field out of unstructured output. -v prints nothing (a
line selected by NOT matching has no matched text), and
-c wins over -o because "how many lines" and "show me
each match" are different questions.
-q, --quiet, --silent
Print nothing at all and stop at the first match. Exists
for its exit status: if (grep -q PAT file) then ...
-H, --with-filename
Always prefix output with the filename. The counterpart
to -h; the prefix otherwise appears only when there is
more than one file to disambiguate.
-F, --fixed-strings
Treat PATTERN as a literal string, not a regex.
-w, --word-regexp
Match only whole words (the pattern is anchored at a
word boundary on both sides).
-E, --extended-regexp
Accepted and ignored: cshw's grep is already extended.
--pcre2 Use the PCRE2 engine explicitly, for lookahead,
lookbehind and the rest of the fuller dialect.
Short flags bundle: -ci, -rl, -oE and so on. An unrecognised flag is an
error (exit 2), never a pattern.
grep error log.txt
Find lines containing "error" in log.txt.
grep -i ERROR log.txt
Case-insensitive search for "error".
grep -n "TODO" *.cpp
Show line numbers for TODO comments in C++ files.
grep -r "password" .
Recursively search for "password" in current directory tree.
grep -v "^#" config.txt
Show lines NOT starting with # (non-comments).
grep "^\s*$" file.txt
Find empty or whitespace-only lines.
type log.txt | grep -i warning
Search piped input for warnings (case-insensitive).
grep "[0-9]{3}-[0-9]{4}" contacts.txt
Find phone number patterns (###-####).
grep -rn "class\s+\w+" src/
Find class definitions in source directory.
dir /b | grep "\.txt$"
Filter dir output to show only .txt files.
grep "^(GET|POST)" access.log
Find HTTP GET or POST requests in log.
grep -l "main" *.cpp
List .cpp files containing "main".
grep -oE "[0-9]+" version.txt
Print just the numbers, one per line, not the lines they sit on.
grep -q "ERROR" app.log && echo "something went wrong"
Test for a match without printing anything.
0 One or more matches were found 1 No matches were found 2 Error occurred (file not found, invalid regex, etc.)
PCRE2 Regular Expression Quick Reference:
. Any character (except newline)
^ Start of line
$ End of line
* Zero or more of preceding
+ One or more of preceding
? Zero or one of preceding
[abc] Character class (a, b, or c)
[^abc] Negated class (not a, b, or c)
[a-z] Character range
\d Digit [0-9]
\w Word character [a-zA-Z0-9_]
\s Whitespace
\b Word boundary
(x|y) Alternation (x or y)
(...) Grouping
{n} Exactly n occurrences
{n,m} Between n and m occurrences
(?=...) Positive lookahead
(?!...) Negative lookahead
(?i) Case-insensitive mode (inline)
CSHW's grep uses PCRE2 with JIT compilation for optimal performance on large files. The JIT compiler provides near-native speed for complex patterns.
hash back to top ↑create or manipulate an associative array (hash) variable
hash <name>
hash <name> <key>=<value> ...
hash set <name> <key> <value>
hash get <name> <key>
hash has <name> <key>
hash keys <name>
hash list <name>
hash size <name>
Creates and manipulates string-keyed hash variables. The bare form declares: `hash config` makes an empty hash, and trailing `key=value` pairs seed it.
Everything else is a subcommand. Elements are read with `$name[key]` -- the same bracket syntax `array` uses, because the two differ in what goes inside the brackets, not in the punctuation. There is no brace form: `$config{name}` is not a hash reference, it is `$config` followed by the literal text `{name}`.
`get`, `has` and `size` also publish their answer in `$result`, so a script can use it without capturing output. `hash has` additionally sets the exit status -- 0 when the key is present, 1 when it is not -- so it reads naturally in a conditional.
<name> Hash name. Same rules as scalar variable names.
<key>=<value> Optional initial entries for the declaration form.
set NAME KEY VALUE
Store VALUE under KEY, creating NAME if needed.
get NAME KEY Print the value for KEY (empty if absent) and set
$result to it.
has NAME KEY Print 1 or 0, set $result to the same, and set the
exit status to 0 (present) or 1 (absent).
keys NAME Print every key, one per line, in sorted order.
list NAME Print every entry as "key = value", one per line.
size NAME Print the number of entries and set $result to it.
hash users alice=admin bob=user
echo "alice is $users[alice]"
hash settings
hash set settings theme dark
hash set settings font Consolas
hash list settings
hash has settings theme
if ($status == 0) then
echo "theme is $settings[theme]"
endif
hash size settings
echo "$result entries"
0 Hash declared / updated, or (for `has`) the key was present.
1 Bad name, malformed key=value pair, or (for `has`) the key
was absent.
Declaration vs subcommand: The first operand is matched against the subcommand names first, so the bare declaration form cannot name a hash `set`, `get`, `has`, `keys`, `list` or `size`. `hash set set KEY VALUE` still reaches such a hash -- only the shorthand is unavailable for those six names.
Keys are sorted: Entries live in a sorted map, so `hash keys` and `hash list` print in key order, not insertion order.
Re-declaring is safe: `hash config` on an existing hash keeps its contents, so a sourced script that declares its hashes at the top can be sourced twice.
For integer-indexed arrays, see `array`. The two styles are distinct: `array` indexes by position, `hash` by string key. Both read back with $name[...].
hashstat back to top ↑display command hash table statistics
hashstat
Displays statistics about the command hash table, including the number of entries, hits, misses, and efficiency information.
hashstat
# Hash table statistics:
# Entries: 45
# Hits: 234
# Misses: 12
# Hit rate: 95.1%
0 Success
Statistics Shown: - Number of cached command paths - Cache hit count (found in hash) - Cache miss count (required PATH search) - Hit rate percentage
Performance Tuning: High miss rates might indicate: - Commands not in expected locations - Frequent PATH changes - Need to run rehash
Debugging: Use hashstat to understand shell command lookup performance.
head back to top ↑output the first part of files
head [options] FILE
head -n COUNT FILE
command | head [options]
Outputs the first part of files or piped input. By default, prints the first 10 lines. Useful for previewing files or limiting output.
FILE File to read from.
-n COUNT Output the first COUNT lines (default: 10).
-COUNT Shorthand for -n COUNT (e.g., -20).
-c COUNT Output the first COUNT bytes instead of lines.
head file.txt
Display first 10 lines of file.txt.
head -n 20 log.txt
Display first 20 lines.
head -50 data.csv
Display first 50 lines (shorthand).
dir /s | head -n 30
Show first 30 lines of dir output.
head -c 100 binary.dat
Show first 100 bytes.
type largefile.txt | head
Preview beginning of a large file.
0 Success 1 File not found 2 Read error
Default Lines: Without -n, head outputs 10 lines by default.
Binary Files: Use -c for binary files where line concepts don't apply.
Piping: head is commonly used at the end of a pipeline to limit output: find . -name "*.log" | head -n 5
help back to top ↑display command help
help
help COMMAND
Displays brief help information for shell commands. Without arguments, lists all available built-in commands. With a command name, shows usage syntax for that command.
COMMAND Command to get help for.
help
List all built-in commands.
help cd
Show brief help for cd command.
help grep
Show brief help for grep command.
0 Success 1 Command not found
help vs man: - help: Brief usage summary (one or two lines) - man: Comprehensive documentation with examples
Quick Reference: Use help for quick syntax reminders: help tar # tar -c|-x|-t [-z] [-v] -f ARCHIVE [FILES...]
Finding Commands: 'help' without arguments shows all commands, useful for discovering available functionality.
Command Categories: Built-in commands cover: - File operations (dir, copy, del, mv, type) - Navigation (cd, pushd, popd, pwd) - Variables (set, unset, setenv) - Job control (jobs, bg, fg, kill) - And many more
hexdump back to top ↑display file contents in hexadecimal
hexdump [options] FILE
command | hexdump [options]
Displays file contents in hexadecimal format with optional ASCII representation. Essential for examining binary files, debugging data formats, and analyzing file structures.
FILE File to display.
-C Canonical format: hex + ASCII (most common).
-n LENGTH Display only first LENGTH bytes.
-s OFFSET Skip OFFSET bytes from start.
-v Display all data (don't suppress duplicate lines).
hexdump -C file.bin
Display file in canonical hex+ASCII format.
hexdump -C -n 256 program.exe
Show first 256 bytes of executable.
hexdump -C -s 1024 -n 512 file.dat
Show 512 bytes starting at offset 1024.
echo "Hello" | hexdump -C
See hex representation of text.
hexdump -C image.png | head -20
Preview beginning of PNG file.
0 Success 1 File not found 2 Read error
Output Format (Canonical -C): 00000000 48 65 6c 6c 6f 20 57 6f 72 6c 64 0a |Hello World.| OFFSET HEX BYTES (16 per line) ASCII
Reading Hex: - Each hex pair represents one byte (00-FF) - ASCII column shows printable characters - Non-printable bytes shown as '.'
File Signatures: Many file formats have distinctive headers ("magic numbers"): - PNG: 89 50 4E 47 0D 0A 1A 0A - PDF: 25 50 44 46 (% P D F) - EXE: 4D 5A (MZ) - ZIP: 50 4B 03 04
history back to top ↑display command history
history
history [N]
history -c
Displays the list of previously executed commands. CSHW maintains a history of commands entered during the current session and optionally across sessions if persistence is enabled.
The history command is invaluable for recalling previous commands, understanding what operations were performed, and repeating or modifying past commands.
N Display only the last N commands.
-c, --clear Clear the command history.
history
Display all commands in history.
history 20
Display the last 20 commands.
history -c
Clear all command history.
0 Success
$histchars: The character that introduces a history reference, replacing `!`:
set histchars = "," then ,, repeats the previous command
csh takes a two-character value, the second for `^old^new` quick substitution. Only the first is honoured here, because quick substitution is not implemented -- accepting the value and applying half of it silently would be worse than saying so.
History substitution happens at the interactive prompt only. A `!` in a script file is literal, whatever histchars says.
History Navigation: Use the up/down arrow keys at the command prompt to navigate through previous commands.
History Size: The shell maintains a configurable maximum number of history entries. Older entries are removed when the limit is reached.
History Persistence: History is saved to %APPDATA%\cshw\history and restored on shell startup. Use the history_max shell variable to configure the maximum number of entries persisted.
Command Recall: Previous commands can be recalled and edited before re-execution using the arrow keys.
Duplicate Handling: Consecutive duplicate commands may be stored only once to keep the history clean.
hostname back to top ↑display the system hostname
hostname [options]
Displays the computer's network hostname. By default, shows the NetBIOS name. Options allow retrieving the DNS hostname or fully qualified domain name (FQDN).
-f, --fqdn Display fully qualified domain name (e.g., host.domain.com)
-d, --dns Display DNS hostname
hostname
MYCOMPUTER
hostname -f
mycomputer.corp.example.com
hostname -d
mycomputer
This command displays the hostname but cannot change it. To change the hostname on Windows, use: - System Properties > Computer Name - PowerShell: Rename-Computer -NewName "NewName" - Control Panel: sysdm.cpl
The difference between name types: - NetBIOS name: Legacy Windows network name (up to 15 characters) - DNS hostname: Modern hostname used by DNS - FQDN: Complete DNS name including domain suffix
install back to top ↑install cshw onto the system
install [path] [/user]
Copies cshw.exe and its supporting files (man pages, runtime DLLs) to an install location, then updates PATH so `cshw` is invocable by name from any prompt.
By default the install is system-wide (under Program Files, writes HKLM PATH) and requires admin. With /user, the install is per-user (under %LOCALAPPDATA%, writes HKCU PATH) and runs without elevation.
path Optional explicit install directory. If omitted, uses
a sensible default based on whether /user is set.
/user Install per-user under %LOCALAPPDATA%. No admin needed.
Modifies only HKCU PATH.
install
System-wide install to Program Files. Requires admin.
install /user
Per-user install to %LOCALAPPDATA%\Tropibyte\cshw.
install "C:\tools\cshw"
System-wide install to an explicit directory.
0 Install succeeded.
1 Permission denied (not running elevated for a system
install) or copy/registry write failure.
The Inno Setup installer (cshw-setup-X.Y.Z.exe) is the recommended distribution mechanism for end users -- it adds file associations, Windows Terminal integration, and an uninstaller. This `install` command is the lightweight in-shell alternative for scripted setups or developer workflows.
isWindows back to top ↑test whether the shell is running on Windows
isWindows
iswindows
A platform predicate: reports whether the running shell is on Windows, so a portable csh/tcsh script can take one path on Windows and another on Unix/Linux. On cshw -- a native Windows shell -- it is effectively always true: it prints 1, sets the $isWindows variable and $result to 1, and succeeds (exit status 0). A csh/tcsh on Unix or Linux has no Windows to report, so the equivalent test is false there; guarding Windows-specific code with isWindows lets the same script do the right thing on each platform. Both spellings work.
Usable two ways: as a truth value in a csh `if (...)` test (the value is 1), and as an exit-status predicate for `&&` / `||` chaining (success on Windows).
if (isWindows) then
set sep = ";" # Windows PATH separator
else
set sep = ":" # Unix / Linux
endif
isWindows && echo "on Windows"
0 On Windows -- the true result (and the value 1 is printed and stored
in $isWindows / $result). On cshw this is always the case.
1 On a non-Windows shell -- the false result. cshw never reports this,
since it only runs on Windows.
Because cshw only runs on Windows, isWindows never reports false here; it exists so cross-platform csh/tcsh scripts stay clean.
jobs back to top ↑display status of background jobs
jobs
jobs [options]
Displays the status of jobs that have been started in the background. Each job is identified by a job number and shows its current state (running, stopped, completed) along with the command that started it.
Job control allows you to run multiple commands simultaneously, switching between foreground and background execution as needed.
-l Long format - include process IDs.
-p Print only process IDs.
-r Display only running jobs.
-s Display only stopped jobs.
jobs
List all background jobs.
jobs -l
List jobs with process IDs.
jobs -r
Show only currently running jobs.
0 Success
Job States: RUNNING - Job is currently executing STOPPED - Job has been suspended (Ctrl+Z) COMPLETED - Job has finished execution
Job Numbers: Jobs are assigned sequential numbers starting from 1. These numbers can be used with fg, bg, kill, and other job control commands.
Starting Background Jobs: To start a command in the background, append & to the command line: longprocess.exe &
Current and Previous Jobs: The most recently backgrounded job is the "current" job (+). The previously backgrounded job is the "previous" job (-).
fg, bg, kill, stop, processlist
kad back to top ↑kill process and secure-delete its executable (alias for killanddel)
kad <pid_or_name>
`kad` is identical to `killanddel`. See `man killanddel` for full documentation.
kill back to top ↑terminate processes
kill PID
kill -9 PID
kill %JOBID
Terminates a process by its process ID (PID) or job number. By default, kill attempts a graceful termination, but can forcefully terminate processes that don't respond.
kill is essential for managing runaway processes, stopping hung programs, and controlling background jobs.
PID Process ID to terminate (numeric).
%JOBID Job number from jobs command (prefixed with %).
-9, -KILL Forcefully terminate (no cleanup allowed).
-15, -TERM Request graceful termination (default).
/f Force termination (same as -9).
/t Terminate process tree (include child processes).
kill 1234
Terminate process with PID 1234.
kill -9 1234
Forcefully terminate process 1234.
kill %1
Terminate job number 1.
kill /f /t 1234
Force-kill process 1234 and all its children.
processlist | grep notepad
# Find notepad's PID, then:
kill 5678
Terminate notepad process.
0 Success - process terminated 1 Process not found 2 Access denied (need administrator privileges) 3 Invalid argument
Process Trees: Some processes spawn child processes. Use /t to terminate the entire process tree, not just the parent.
Access Rights: You can only kill processes you own, unless running as Administrator. System processes may require elevated privileges.
Graceful vs Forced: Without -9, kill sends a termination request allowing the process to clean up (save files, release resources). With -9, the process is immediately terminated with no cleanup.
Finding PIDs: Use 'processlist' or 'ps' to find process IDs, or use Task Manager.
Hung Processes: If a process doesn't respond to normal kill, use -9 to force termination.
processlist, jobs, bg, fg, killanddel
killanddel back to top ↑kill processes and securely delete executables
killanddel [options] EXECUTABLE_PATH
kad [options] EXECUTABLE_PATH
Aliases: kad
Terminates all processes running a specified executable and securely deletes the file. Designed for removing malware that respawns quickly after deletion.
The command performs these steps: 1. Find all processes running the executable 2. Forcefully terminate those processes 3. Open file with exclusive access (prevent respawn) 4. Overwrite file contents with zeros 5. Delete the file
EXECUTABLE_PATH Path to the executable to kill and delete.
/v, /verbose Show detailed progress.
/a, /ancestors Show process ancestry (parent, grandparent).
/r:N, /recurse:N
Also kill N levels of ancestor processes.
/admin Run with elevated Administrator privileges.
/f, /force Don't prompt for confirmation.
/dry Dry run - show actions without performing them.
killanddel C:\temp\malware.exe
Kill process and delete file.
kad C:\temp\malware.exe
Short form of killanddel.
kad /v /a C:\temp\malware.exe
Verbose output with ancestry display.
kad /r:1 C:\temp\malware.exe
Also kill the parent process.
kad /dry C:\temp\suspicious.exe
Preview what would happen.
kad /admin C:\temp\malware.exe
Run as Administrator for system-level access.
0 Success - process killed and file deleted 1 File not found 2 Access denied (may need /admin) 3 Process termination failed 4 File deletion failed
Secure Deletion: Before deleting, the file is overwritten with zeros. This prevents simple file recovery tools from retrieving the original content.
Process Ancestry: The /a flag shows the process tree, helpful for identifying if malware has spawned from or infected another process.
Recursive Killing: /r:1 kills the malware's parent process. /r:2 kills parent and grandparent. Use carefully - you may kill legitimate processes.
Administrator Rights: Many malware processes run with elevated privileges. Use /admin to ensure you can terminate them.
Respawn Prevention: By opening the file exclusively before killing processes, killanddel prevents watchdog processes from respawning the malware.
Dry Run: Always use /dry first on unfamiliar malware to see what will happen before actually killing processes.
lc back to top ↑count lines in files
lc FILE
lc PATTERN
lc [/s] [/q] PATTERN[,PATTERN,...]
lc [/s] [/q] DIR\PATTERN[,PATTERN,...]
linecount [options] PATTERN...
Counts the number of lines in files matching the specified pattern(s). Supports wildcards, multiple patterns, and recursive directory traversal. This is useful for quickly determining the size of a codebase or project.
When counting multiple files, displays the line count for each file followed by a summary showing total lines and file count.
The command name 'linecount' is an alias for 'lc'.
FILE Single file to count lines in.
PATTERN Wildcard pattern (e.g., *.cpp, *.h, file?.txt).
Supports * (match any characters) and ? (match
single character).
/s, -s, -r, --recursive
Recurse into subdirectories. Without this flag,
only files in the specified directory are counted.
/q, -q, --quiet
Quiet mode. Only display the final total, not
individual file counts. Useful for scripts.
Multiple patterns can be specified:
- Comma-separated: *.cpp,*.h,*.c
- As separate arguments: *.cpp *.h *.c (if shell supports)
lc readme.txt
Count lines in a single file.
lc *.cpp
Count lines in all .cpp files in current directory.
lc /s *.cpp
Count lines in all .cpp files, including subdirectories.
lc /s *.cpp,*.h
Count lines in all C++ source and header files recursively.
lc /s /q *.c,*.h
Quietly count all C files recursively (only show total).
lc src\*.cpp
Count lines in .cpp files in the src subdirectory.
lc /s src\*.cpp,*.h,*.c
Count C/C++ files in src directory tree.
lc /s *.cpp,*.h,*.c,*.rc,*.vcxproj
Count all Visual Studio C++ project source files.
linecount /s *.py
Count Python files recursively (using alias).
0 Success 1 Syntax error or no files found
Codebase Size Estimation: Use lc to get accurate line counts for your project instead of guessing. Example for a typical C++ Visual Studio project:
lc /s *.cpp,*.h,*.c,*.rc,*.vcxproj,*.props
This counts all source files, resource files, and project files.
Pattern Matching: Patterns are case-insensitive on Windows. The following wildcards are supported: * Match zero or more characters ? Match exactly one character
Examples: *.cpp All files ending in .cpp test*.h Header files starting with "test" file?.txt file1.txt, fileA.txt, but not file10.txt
Performance: For large codebases, consider using /q (quiet) mode to reduce output overhead. The line counting itself is efficient, reading files line by line without loading entire files into memory.
Binary Files: Binary files will be counted but may report inaccurate line counts since they don't contain proper line endings. For best results, use patterns that match only text files.
Comparison with wc: - wc: UNIX-style word count for single file (lines, words, bytes) - lc: Line count optimized for multiple files with patterns
Empty Files: Empty files are included in the file count but contribute 0 lines.
library back to top ↑load CSHW script as procedure library
library FILE
library FILE...
Loads a CSHW script file and registers all procedures defined in it as available commands. This allows you to create reusable procedure libraries that can be loaded on demand.
FILE Script file(s) containing procedure definitions.
library utils.csh
Load procedures from utils.csh.
library lib/math.csh lib/string.csh
Load multiple libraries.
# File: mylib.csh
proc greet(name)
echo "Hello, $name!"
endproc
proc add(a, b)
return ($a + $b)
endproc
# Then:
library mylib.csh
greet "World"
set result=$(add 5 3)
# result = 8
0 Success 1 File not found 2 Syntax error in library
Procedure Registration: All 'proc' definitions in the file become available as commands after loading. They're registered in the global procedure registry.
Load Order: Libraries are loaded in order. Later definitions override earlier ones with the same name.
Dependencies: If a library depends on other libraries, load dependencies first: library base.csh library extended.csh # May use procs from base.csh
vs source: - library: Registers procedures for later use - source: Executes commands immediately
Best Practices: - Libraries should only contain procedure definitions - Use descriptive procedure names - Document procedures with comments - Group related procedures in one file
Reloading: Loading the same library again updates procedure definitions.
source, proc, call
limit back to top ↑display resource limits
limit
limit RESOURCE
Displays the resource limits in effect for the shell, together with the current process's resource usage and system-wide memory figures.
LIMITS ARE READ-ONLY HERE. tcsh's `limit RESOURCE VALUE` form is accepted at the command line and refused with a message naming the resource, because Windows has no per-process rlimit for the shell to lower. Earlier versions of this page showed `limit filesize 100m` and `limit cputime 60` as working examples. They were not; both report "cannot be set on Windows" and exit 1.
With no argument, limit prints every resource, then this process's usage, then system memory. With a resource name, it prints that one line.
RESOURCE Resource to report:
cputime CPU time
filesize Maximum file size
datasize Data segment size
stacksize Stack size (from the PE header)
coredumpsize Core dump size
memoryuse Current working set
vmemoryuse Virtual address space
descriptors Max open file descriptors (CRT limit)
concurrency Logical processors available
maxproc Process count limit
limit
Display all limits, this process's usage, and system memory.
limit filesize
Display the file size limit alone.
limit descriptors
How many file descriptors the CRT will hand out.
limit stacksize
The reserved stack size for this image.
0 Reported successfully.
1 Unknown resource name, or a value was supplied (limits
cannot be set).
Why read-only: UNIX rlimits are a per-process kernel facility with no Windows equivalent a shell can apply to itself. Windows constrains processes with Job Objects, which are assigned from outside and govern a whole job rather than one process lowering its own ceiling. Accepting a limit cshw cannot enforce would be worse than declining to set it.
Bounding a child: To cap what a program may consume, launch it inside a Job Object rather than expecting `limit` to change anything the shell passes down.
unlimit: `unlimit` exists as a companion and likewise removes nothing; it prints where these figures come from.
Which numbers are measured: memoryuse and vmemoryuse come from this process. descriptors is the CRT's table size. concurrency is the logical processor count. stacksize is the reserve in the PE header. cputime, filesize, coredumpsize and maxproc report "unlimited" because nothing in Windows limits them for an ordinary process.
Inherited limits: Child processes inherit the environment, not a limit set -- there is no limit set to inherit.
linecount back to top ↑count lines in files (alias for lc)
linecount FILE
linecount [/s] [/q] PATTERN[,PATTERN,...]
Alias for the lc command. Counts lines in files matching patterns. See 'man lc' for complete documentation.
linecount /s *.cpp,*.h
Count all C++ source files recursively.
linecount /q *.py
Quietly count Python files (total only).
local back to top ↑declare a variable in the current procedure's scope
local <name> [= <value>]
local <name1> <name2> ... <nameN>
Declares one or more variable names as local to the current proc. The variable disappears when the proc returns, restoring any global of the same name that was previously visible.
Without an `= value`, the variable is declared but left empty (and unset when the proc returns).
`local` outside a proc is a no-op for scoping purposes but still performs any assignment.
<name> Variable name. Multiple names can be declared in one
`local` statement.
<value> Optional initial value (only when one name is given).
proc square
local result
@ result = $1 * $1
echo $result
endproc
set result = "global-result"
square 5 # prints 25
echo $result # still "global-result" -- local didn't leak
proc tmp
local a b c
set a = 1
set b = 2
set c = 3
echo $a $b $c
endproc
0 Always.
By default, `set` inside a proc already creates a local variable. The explicit `local` is mainly useful for: - Documenting intent ("these names are scoped to this proc") - Declaring multiple locals at once - Reserving a name BEFORE any conditional assignment to it, so later `set name = ...` doesn't accidentally hit a global of the same name when the conditional path skips the first write.
The counterparts that REACH OUT of local scope are `share` (writes through to the global namespace from a coroutine or proc) and the explicit global-variable accessors.
log back to top ↑tee stdout and stderr to a file while still showing them
log FILE
log -a FILE
log off
log
Starts copying everything the shell produces -- standard output AND standard error, from builtins and from external programs alike -- into FILE, while you go on seeing it on screen.
This is not the same as `> file`, and the difference is the reason the command exists. A redirect captures ONE stream. Run something that reports problems on stderr and redirect only stdout, and the file fills with the successes while the terminal fills with the complaints -- the two halves of the story land in different places, and the half you are looking at is the alarming one.
`>&` captures both, but it is csh-specific spelling and it is the thing nobody remembers at the moment they need it. `log` is meant to be reachable without thinking: turn it on, do the thing that misbehaves, turn it off, attach the file.
FILE Start logging to FILE, replacing anything already in it.
-a, --append Append instead of replacing. Useful across several runs
of the same reproduction.
off Stop logging, flush and close the file.
(none) Report whether logging is on and where it is going.
Exit status is 0 when logging, 1 when not, so
`log && echo capturing` works.
What is captured: - everything the shell itself prints, including error messages - everything a builtin prints on either stream - everything an external program prints on either stream, because the child inherits the same destination
What is NOT captured, deliberately: - the prompt, and the characters you type. Those are terminal echo, not output; a log full of half-typed lines and cursor movement is harder to read than one without them. - anything a command redirected somewhere else. `cmd > out.txt` still writes to out.txt and not to the log, exactly as it would without logging.
The file is flushed after every write, so it survives the shell hanging or being killed -- which is the case people usually turn logging on for.
Logging to a second file while the first is active is refused rather than silently switched. Two destinations in one session is much more likely to be a mistake than an intention.
log session.txt
Start capturing.
log session.txt
source run_all_tests.cshw
log off
Capture a whole test run -- passes and diagnostics together, in one
file, in the order they happened.
log -a repro.txt
Add this run to a file that already holds an earlier one.
log
"logging to session.txt", or "not logging".
cshw -log session.txt myscript.cshw
The same from the command line, covering the startup files too --
which a `log` command inside the script cannot reach.
0 Started, stopped, or logging is on 1 Not logging (for a bare `log`), or the file could not be opened
login back to top ↑log in as a different user
login [USERNAME]
Initiates a login session as the specified user. This command is primarily for compatibility with UNIX shells. On Windows, actual user switching requires different mechanisms.
USERNAME User to log in as.
login
Prompt for username and password.
login administrator
Log in as administrator.
0 Success 1 Authentication failed 2 User not found
Windows Limitations: On Windows, true user switching within a console session has limitations. For full user switching, use: - Windows logoff/logon - runas command - Fast User Switching
runas Alternative: For running commands as another user: runas /user:DOMAIN\username command
Security: Credentials entered at the login prompt should be handled securely. Be cautious on shared or untrusted systems.
logout back to top ↑end a login shell
logout
Ends a LOGIN shell -- the session's first shell, started with -l or --login. In any other shell this is an error:
Not login shell.
and the shell keeps running, at status 1. That is tcsh's behaviour, and it is what makes this something other than a synonym for `exit`: ending a login shell also runs ~/.logout, and ending a subshell must not.
Use `exit` for any shell. Use `logout` when you specifically mean "end this session", and want to be told if you are somewhere else.
logout
End the session, running ~/.logout on the way out.
cshw -l
Start a login shell, where logout is meaningful.
Does not return in a login shell -- the shell exits, keeping whatever status was in effect. A ~/.logout that runs commands does not change it.
1 Not a login shell. Nothing happened.
What makes a login shell here: cshw is a login shell when it was started with -l or --login. It is DECLARED, not detected: tcsh knows because /bin/login execs it with an argv[0] of "-tcsh", and nothing on Windows does that, so there is no signal to read. The Start-menu shortcut passes -l; a cshw started from inside another cshw does not, which is exactly the distinction .login and .logout exist to make.
`if ($?loginsh) then ... endif` is how a script asks.
Running jobs: If background jobs are running you may be warned. Use `jobs` to see them, then decide whether to wait or exit anyway.
lp back to top ↑send a file to a printer, or render it to a file
lp [-d PRINTER] [MODE] [FILE...]
lp --pdf FILE [OPTIONS] [FILE...]
lp --xps FILE [OPTIONS] [FILE...]
lp --image FILE [OPTIONS] [FILE...]
Sends FILE to a printer. With no FILE, reads standard input, so lp sits at the end of a pipeline the way it does everywhere else:
fmt -w 65 letter.txt | pr -h "Draft" | lp
lp is the System V spelling and lpr is the BSD one. They are the same command here, and both accept -d and -P for the destination, so a script ported from either world runs unchanged.
With no printer named, the system default is used. `lpstat -d` shows it.
-d NAME, -P NAME Printer to use. Default: the system default.
-n N, --copies N Number of copies.
-T TEXT, --title Job name, and the page title under --gdi.
Mode -- how the bytes reach the page:
(default) RAW. The file is sent untouched.
--raw Same, said explicitly.
--text The spooler renders plain text (datatype TEXT).
--gdi cshw renders, using the layout options below.
Layout, for --gdi and --image:
--font NAME Default Consolas.
--size POINTS Default 10.
--margin INCHES Default 0.5.
--landscape Rotate the page.
Output to a file instead of a printer:
--pdf FILE Through Microsoft Print to PDF.
--xps FILE Through Microsoft XPS Document Writer.
--image FILE Rendered by cshw. No printer involved.
--imagetype T tiff | png | jpg | bmp. Default tiff.
--dpi N Default 200.
--tiff-compression C g4 | lzw | none. Default g4.
lp report.ps
RAW: the bytes go straight to the printer. Right when the file is
already PostScript or PCL.
lp --text notes.txt
Let the spooler render the text.
lp --gdi --font "Courier New" --size 9 --margin 1.0 notes.txt
Render it here, with control over the layout.
lp --pdf out.pdf notes.txt
lp --xps out.xps notes.txt
To a file, with no Save-As dialog.
lp --image scan.tif --dpi 300 notes.txt
A multi-page TIFF at 300 dpi.
fmt -w 65 letter.txt | pr -h "Draft" | lp --pdf draft.pdf
Reflow, paginate, render.
0 The job was submitted, or the file was written 1 Failure -- the message says which
Choosing a mode -- and why lp will not choose for you: RAW is the default because it is the only mode that does not touch your data, and a caller sending PostScript wants exactly that. It is also the mode that fails most confusingly: a printer accepts RAW quite happily and then prints pages of garbage, because acceptance happens in the SPOOLER and interpretation happens in the DEVICE.
No Win32 API answers "does this device understand PostScript?", so lp does not guess. `lpstat -l` reports what it found -- driver, port, print processor, default datatype and the datatypes the processor accepts -- and you choose. A wrong guess here would waste a ream of paper quietly.
When a datatype is refused: The print processor's list is necessary but not sufficient: the DRIVER can refuse a datatype the processor advertises. On a stock Windows 11 machine winprint offers TEXT for every printer, yet Print to PDF, the XPS writer and OneNote all reject it with error 1804, while Fax accepts it. lp says so and names the way out rather than printing a bare number.
Multi-page image output: TIFF holds every page in one file. PNG, JPG and BMP cannot -- they are single-image formats -- so those write ONE FILE PER PAGE:
lp --image report.png --imagetype png -> report-pg1.png
report-pg2.png
report-pg3.png
Numbers are zero-padded to the width of the highest page, so a twelve-page document gives report-pg01.png .. report-pg12.png and the names still sort correctly. Every page is suffixed, including page 1 of a one-page document, so the name never depends on how long the document happens to be. lp prints each file it wrote.
Image size: A letter page of text, measured. TIFF-G4 is bilevel and dramatically smaller; JPEG is a poor fit for text, being both larger and lossy on the sharp edges text is made of.
DPI TIFF-G4 PNG JPG BMP 96 12 KB 58 KB 153 KB 3.4 MB 200 34 KB 344 KB 964 KB 15 MB 300 50 KB 435 KB 1.4 MB 34 MB
lpadmin back to top ↑Printer administration.
lpc back to top ↑control a print queue
lpc status [-P PRINTER]
lpc stop [-P PRINTER]
lpc start [-P PRINTER]
lpc purge [-P PRINTER]
Inspects and controls a printer's queue: whether it is accepting work, and what to do about the jobs already in it.
status Report whether queuing is enabled, and how many entries.
stop Pause the queue. Jobs accumulate; nothing prints.
start Resume it.
purge Discard every job in the queue.
-P NAME, -d NAME Printer. Default: the system default.
lpc status
Microsoft Print to PDF:
queuing is enabled
0 entries
lpc stop -P "Front Desk"
Hold everything while the paper is changed.
lpc start -P "Front Desk"
lpc purge -P "Front Desk"
Throw away what is queued.
0 The action succeeded 1 It did not -- the message says why
stop, start and purge change state shared with every other user of that printer, so they need the rights to manage it and fail with error 5 (access denied) without them. lpc says so explicitly and names sudo rather than failing obscurely. cshw never elevates itself.
purge is not undoable. lpq first if you want to know what you are about to discard.
lpq back to top ↑list the jobs in a print queue
lpq [-P PRINTER]
Shows what is waiting in a printer's queue: job id, owner, status, size and document name. With no printer named, the system default is used.
The job id is what lprm and cancel take.
-P NAME, -d NAME Printer to inspect. Default: the system default.
lpq
Job Owner Status Size Document
17 tarie spooling 20480 report.txt
lpq -P "Microsoft Print to PDF"
lprm `lpq | awk 'NR>1 {print $1}'`
Remove every job the queue is showing.
0 The queue was read (including when it is empty) 1 The printer could not be opened
Status values come from the spooler: queued, spooling, printing, paused, printed, deleting, error. A job can sit in "spooling" for some time on a slow link; that is the spooler's business, not the printer's.
lpr back to top ↑send a file to a printer (BSD spelling of lp)
lpr [-P PRINTER] [MODE] [FILE...]
The BSD name for lp. They are the SAME command in cshw, with the same options and the same behaviour -- both accept -P and -d for the destination so a script written against either tradition runs unchanged.
Historically lpr (BSD) and lp (System V) were separate programs with gratuitously different flags. There is no reason to reproduce that here.
See lp(1) for the full description: the three modes (RAW, --text, --gdi), the file targets (--pdf, --xps, --image), layout options and image formats.
-P NAME, -d NAME Printer to use
-n N, --copies N Number of copies
-T TEXT, --title Job name
See lp(1) for --raw, --text, --gdi, --pdf, --xps, --image, --imagetype,
--dpi, --tiff-compression, --font, --size, --margin and --landscape.
lpr report.ps
lpr -P "Front Desk" --text notes.txt
cat notes.txt | lpr --gdi
0 The job was submitted, or the file was written 1 Failure
lprm back to top ↑remove jobs from a print queue
lprm [-P PRINTER] JOBID...
lprm [-P PRINTER] -a
Removes jobs from a printer's queue. Job ids come from lpq. With -a every job in the queue is removed.
`cancel` is the same command under its System V name.
-P NAME, -d NAME Printer. Default: the system default.
-a, --all Remove every job in the queue.
lpq
lprm 17
lprm: removed job 17 from Microsoft Print to PDF
lprm -a
Clear the whole queue.
lprm -P "Front Desk" 12 13 14
0 Every named job was removed 1 At least one could not be
Removing someone else's job needs the rights to manage the printer, and fails with error 5 (access denied) without them. cshw never elevates itself; run an elevated shell, or use sudo.
A job that has already finished printing is gone from the queue and cannot be removed -- lprm reports that rather than pretending it worked.
lpstat back to top ↑show printers and what they will accept
lpstat [-l] [-d]
Lists the printers this machine knows about and marks the default. With -l it also reports the driver, port, print processor, default datatype, job count, and the datatypes the print processor will accept.
That last line is the point of the command. It is REPORTED so you can choose a mode for lp; it is never used to guess one.
-l, --long Long form: driver, port, processor, datatype, jobs,
and accepted datatypes.
-d, --default Show only the system default destination.
lpstat
printer Microsoft XPS Document Writer (default)
printer Microsoft Print to PDF
printer Fax
lpstat -d
system default destination: Microsoft XPS Document Writer
lpstat -l
printer Microsoft Print to PDF
driver: Microsoft Print To PDF
port: PORTPROMPT:
processor:winprint
datatype: RAW
jobs: 0
accepts: RAW, RAW [FF appended], RAW [FF auto], NT EMF 1.003,
NT EMF 1.006, NT EMF 1.007, NT EMF 1.008, TEXT, XPS2GDI
0 Always, including when there are no printers
Why this is a report and not a decision: There is no Win32 API that answers "does this device understand PostScript?" Two different things are being confused whenever someone tries to auto-detect:
* EnumPrintProcessorDatatypes says what the SPOOLER will accept. A printer takes RAW happily and then prints garbage, because acceptance happens in the spooler and interpretation happens in the device. * The DRIVER can refuse a datatype the processor advertises. Measured on a stock Windows 11 box: winprint offers TEXT for every printer, yet Print to PDF, the XPS writer and OneNote all reject it with error 1804, while Fax accepts it.
So the 'accepts' line is necessary but not sufficient. Read it, then pick the mode yourself. lp will not guess, and when a datatype is refused it says which one and what to use instead.
ls back to top ↑list directory contents (native, not a shell-out)
ls [OPTION]... [FILE]...
Lists files and subdirectories, following GNU coreutils' ls. Native implementation -- it does NOT shell out to an external ls.exe. With no FILE, lists the current directory.
Output goes to columns when it is heading for a console and to one name per line when it is redirected or piped, which is what GNU does and what makes `ls | wc -l` count files rather than screen rows.
What to list:
-a, --all Include entries starting with '.', and '.' and
'..' themselves. Also shows files Windows marks
hidden.
-A, --almost-all Like -a, but without '.' and '..'.
-d, --directory List the DIRECTORY ITSELF, not its contents.
`ls -ld folder` reports on the folder; `ls -d */`
lists directories without descending into them.
-R, --recursive Descend into subdirectories.
How to show it:
-l Long format: mode, links, owner, group, size,
time, name.
-1 One entry per line.
-C Multi-column, filling down each column.
-x Multi-column, filling across each row.
-m Comma-separated, filled to the terminal width.
-F, --classify Append an indicator: / directory, * executable,
@ reparse point.
-p Append / to directories only.
-Q, --quote-name Enclose each name in double quotes.
-i, --inode Show the file index -- Windows' nearest thing to
an inode. Costs a handle open per entry, so it is
only fetched when asked for.
-s, --size Show the size in 1K blocks.
-h, --human-readable Sizes as 1K, 234M, 2G.
--si The same, in powers of 1000.
-g Like -l, but omit the owner.
-o, -G, --no-group Like -l, but omit the group.
-n, --numeric-uid-gid Like -l with numeric ids.
--full-time Long format with a full ISO timestamp.
--time-style=STYLE long-iso / iso / full-iso select the ISO layout.
Sorting:
(default) By name, case-insensitively.
-t By time, newest first.
-S By size, largest first.
-X By extension.
-v Natural order, so file10 follows file9 rather
than file1.
-U, -f Unsorted -- directory order, which is fastest.
-r, --reverse Reverse whatever order is in effect.
-c Use the creation time (with -l or -t).
-u Use the access time (with -l or -t).
--group-directories-first
Directories before files.
ls
The current directory, in columns.
ls -l
Long form.
ls -lh
...with sizes a person can read.
ls -lt
Newest first -- what changed while you were away.
ls -ld C:\Projects
About the FOLDER: its own mode, owner and date.
ls -lR src
Long, recursive.
ls -1 | wc -l
Count entries. Redirected output is one per line anyway, so the
-1 is only there to say so.
ls *.cshw
A pattern. The shell normally expands this before ls sees it; a
QUOTED pattern is expanded by ls itself.
0 Everything named was listed 1 Something could not be accessed 2 An unrecognized option
Reading `ls -l`:
-rw-r--r-- 1 tarie tarie 4321 Aug 1 21:24 notes.txt drwxr-xr-x 1 tarie tarie 0 Aug 1 21:24 Projects
The first character is the type: '-' a file, 'd' a directory, 'l' a reparse point. The nine that follow are permission bits, synthesized from what Windows actually records -- NTFS has no owner/group/other triad, so the group and other columns mirror the owner's read and execute bits. A read-only file loses its 'w'; anything Windows would execute gains an 'x'. This is the same presentation msys and WSL give an NTFS file.
The timestamp follows GNU: "Mon DD HH:MM" for something within the last six months, "Mon DD YYYY" for anything older -- a year being more use than a clock time once a file is old. --full-time gives the exact ISO form.
Deliberate differences from GNU: * The group column repeats the owner. Windows has no numeric GID, and the security descriptor's primary group is almost never what a reader means by "group". * The link count is always 1. Counting hard links means opening every file, and the cost is not worth a column almost nobody reads. * A QUOTED wildcard is expanded by ls rather than refused. GNU leaves globbing entirely to the shell and errors on a pattern; cshw's ls has always expanded one, and scripts rely on it. * --color is accepted and ignored.
Every other option is either implemented or refused. An unrecognized flag is an ERROR, not a silent no-op -- `ls --colour=auto`, or any typo, used to be accepted and quietly change nothing.
man back to top ↑display manual pages
man [command]
man -k keyword
Displays comprehensive documentation for CSHW shell commands. Man pages provide detailed information including syntax, options, examples, and related commands.
Without arguments, lists all available manual pages.
command Display the manual page for this command.
-k keyword Search manual pages for keyword in names and
descriptions.
man
List all available manual pages.
man grep
Display manual page for grep command.
man cd
Display manual page for cd command.
man -k file
Find commands related to "file".
man -k network
Find network-related commands.
0 Success 1 Manual page not found
Bracket pages: `man [` and `man ]` both show test.man, which documents the pair. The operand has to be recovered from the raw command line: a bare `[` or `]` is stripped before a builtin sees it -- the same handling that lets `[ 1 -eq 1 ]` work -- so `man [` used to run with no arguments at all and list every page in the manual.
Keyword search: `man -k WORD` searches every page's name, summary and description. `-k` alone is a usage error, not a request for the full listing.
Man Page Format: Manual pages are organized into sections: NAME - Command name and brief description SYNOPSIS - Usage syntax DESCRIPTION - Detailed explanation OPTIONS - Available options and switches EXAMPLES - Usage examples EXIT_STATUS - Return codes NOTES - Additional information SEE_ALSO - Related commands
Man Page Location: Manual pages are stored as .man files. The shell searches for them in this order: 1. Directory specified by CSHW_MAN environment variable 2. 'man' subdirectory alongside the shell executable
Comparison with Help: - 'help' provides brief usage information - 'man' provides comprehensive documentation
Creating Man Pages: Man pages use a simple text format with section headers starting with a period (.NAME, .SYNOPSIS, etc.).
CSHW_MAN Directory containing .man files. If set and the
directory exists, man pages are loaded from here
instead of the default location.
md back to top ↑make a directory (alias for mkdir)
md <directory>
`md` is identical to `mkdir`. See `man mkdir` for full documentation.
md5sum back to top ↑compute MD5 message digest
md5sum FILE...
command | md5sum
Computes and displays the MD5 hash (128-bit) of files. MD5 produces a 32-character hexadecimal fingerprint that changes if the file changes.
FILE One or more files to hash.
-c FILE Check MD5 sums against a checksum file.
md5sum file.txt
Compute MD5 hash of file.txt.
md5sum *.iso
Hash all ISO files.
md5sum -c checksums.md5
Verify files against saved checksums.
type data.bin | md5sum
Hash piped input.
md5sum file.zip > file.zip.md5
Save checksum to file.
0 Success (or all checksums verified) 1 Checksum mismatch (verify mode) 2 File not found
Piped input: With no file operand and a redirected stdin, md5sum hashes what it is given and prints "-" in the filename column, the way GNU does. The stream is treated as text and hashed as UTF-8, so the digest matches what GNU produces for the same text. An interactive shell with nothing piped in gets the usage message rather than blocking on the terminal.
Output Format: d41d8cd98f00b204e9800998ecf8427e filename.txt
Security Warning: MD5 is cryptographically broken and should NOT be used for security purposes. Use SHA-256 or SHA-512 for security applications. MD5 is still acceptable for: - Non-security integrity checks - Duplicate file detection - Cache keys
Verification: Create checksum files for later verification: md5sum *.zip > checksums.md5 # Later... md5sum -c checksums.md5
messagebox back to top ↑show a Win32 message box
messagebox <message> [<title>] [<type>]
msgbox <message> [<title>] [<type>]
messagebox <message> [<title>] [/type:<flags>]
Wraps the Win32 MessageBoxW API. Shows a modal message with one of the standard button sets and icons, waits for the user, and reports which button was pressed.
`messagebox` and `msgbox` are two names for one command.
MESSAGE COMES FIRST. The title is optional and defaults to "cshw". Earlier versions of this command took its arguments the other way round -- caption first, title mandatory -- which matched neither this page nor Win32's own MessageBox(hwnd, text, caption, type).
THE BUTTON LANDS IN $status AND $result. Both hold the Win32 ID constant, so a script can branch on either without capturing output. Nothing is printed to stdout; the dialog is the output.
msgbox "Continue?" "Confirm" yesno,question
if ($result == 6) then
echo "user said yes"
endif
Because the exit status carries the button rather than success or failure, `msgbox ... || cmd` fires for anything except OK (1). Test $result, or compare against the specific button you mean.
<message> The body of the message. Required.
<title> Window caption. Default: "cshw".
<type> A number, or a comma-separated list of names. Names
and numbers may be mixed; values combine the same
way the MB_* constants do.
Buttons: ok(0) okcancel(1) abortretryignore(2)
yesnocancel(3) yesno(4) retrycancel(5)
Icons: error/stop(16) question(32)
warning/exclamation(48) info(64)
Other: defbutton1 defbutton2 defbutton3
systemmodal taskmodal topmost
MB_ prefixes are accepted: MB_YESNO reads the same
as yesno.
/type:<flags> The same list as a switch, for the spelling this
page has always documented. Combines with a
positional type rather than replacing it.
An unknown type name is refused before any dialog appears, so a typo
is reported rather than silently producing a plain OK box.
messagebox "Hello, world"
Simple message box titled "cshw".
msgbox "Operation complete" "Status"
Custom title.
msgbox "Continue?" "Confirm" yesno,question
Yes/No prompt with a question icon.
msgbox "Are you sure?" "Confirm" 36
The same thing numerically: 4 (yesno) + 32 (question).
msgbox "File not found" "Error" error
Error icon, OK button.
msgbox "Are you sure?" "Warning" yesnocancel,warning
if ($result == 6) echo "Yes"
if ($result == 7) echo "No"
if ($result == 2) echo "Cancel"
messagebox "Continue?" "Confirm" /type:yesno,question
Switch spelling, same result.
The button pressed, as the Win32 ID: 1 OK 2 Cancel 3 Abort 4 Retry 5 Ignore 6 Yes 7 No
A usage error (no message, too many operands, unknown type name) reports the problem and returns without showing a dialog.
Blocking: The shell waits for the user to click a button. A script running unattended stops here until someone answers.
$result and $status: $result is the one to prefer -- it is not overwritten by the next command's success or failure the way $status is.
GUI Interaction: Message boxes appear in the foreground and take focus. Add topmost if the dialog must sit above other windows.
mkdir back to top ↑create directories
mkdir DIRECTORY
mkdir -p DIRECTORY
md DIRECTORY
Aliases: md
Creates one or more directories. Can create nested directory structures in a single command with the -p option.
DIRECTORY The directory path to create.
-p, --parents Create parent directories as needed. No error if
the directory already exists.
mkdir newdir
Create directory 'newdir' in current location.
mkdir C:\Users\Me\Projects\NewProject
Create directory with absolute path.
mkdir -p deep/nested/directory/structure
Create entire directory tree.
mkdir "My Documents"
Create directory with spaces in name.
md backup
Create 'backup' directory (md is alias for mkdir).
0 Success 1 Parent directory doesn't exist (without -p) 2 Access denied 3 Directory already exists (without -p)
Parent Directories: Without -p, all parent directories must already exist. With -p, missing parents are created automatically.
Permissions: New directories inherit permissions from the parent directory on Windows.
Network Paths: UNC paths (\\server\share\dir) are supported.
mklink back to top ↑create symbolic and hard links
mklink LINK TARGET
mklink /D LINK TARGET
mklink /H LINK TARGET
mklink /J LINK TARGET
Creates symbolic links, hard links, or directory junctions. Links allow a file or directory to appear in multiple locations without copying data.
LINK The name/path of the link to create.
TARGET The file or directory the link points to.
Link types:
(default) Symbolic link to a file.
/D Symbolic link to a directory.
/H Hard link (file only, same volume).
/J Directory junction (directory only).
mklink shortcut.txt C:\Path\To\original.txt
Create symbolic link to a file.
mklink /D ProjectLink C:\Projects\MainProject
Create symbolic link to a directory.
mklink /H hardlink.txt original.txt
Create hard link (shares same data on disk).
mklink /J DevFolder "C:\Users\Me\Development"
Create directory junction.
0 Success 1 Target not found 2 Access denied (need Administrator for symlinks) 3 Link already exists
Link Types Explained:
Symbolic Links (default, /D): - Can point to files or directories - Can span volumes (different drives) - Require Administrator or Developer Mode - Broken if target is deleted
Hard Links (/H): - Files only (not directories) - Same volume only - Shares actual disk space - File persists until ALL hard links deleted - No special privileges required
Directory Junctions (/J): - Directories only - Same volume (usually) - No special privileges required - Similar to symlinks but older technology
Developer Mode: On Windows 10+, enabling Developer Mode allows creating symbolic links without Administrator privileges.
Administrator Required: Creating symbolic links typically requires: - Running as Administrator, OR - Developer Mode enabled, OR - SeCreateSymbolicLinkPrivilege
more back to top ↑display text one screen at a time
more [/s] [FILE]...
command | more
Shows text a screenful at a time, pausing between screens. With no FILE, reads standard input. Several files are shown in turn, each introduced by a *** name *** banner.
The screen size comes from the console, so the page grows and shrinks with the window.
/s Squeeze runs of blank lines down to one.
At the -- More -- prompt:
Enter Show one more LINE
q, Esc Stop
any key Show the next SCREEN
more notes.txt
Page one file.
dir /s | more
Page a long listing.
more /s report.txt
Page it with the blank runs collapsed.
0 The text was displayed 1 One or more files could not be opened
When the output is NOT a console -- redirected to a file, or piped onward -- more passes the text through unpaged and never prompts.
That is what makes it safe to leave in a script. A pager that paused for a keypress in a pipeline would wait for a key that is never coming WHILE HOLDING THE PIPE, so the reader on the other end would wait too, and the script would hang with no output and no explanation.
msgbox back to top ↑display a message box
msgbox MESSAGE
msgbox MESSAGE TITLE
msgbox MESSAGE TITLE TYPE
Displays a Windows message box with the specified message, an optional title, and an optional button/icon configuration. The command waits for the user and reports the button clicked.
`msgbox` and `messagebox` are two names for one command; see `man messagebox` for the full reference. The essentials:
MESSAGE COMES FIRST, the title defaults to "cshw", and the button pressed lands in BOTH $status and $result as the Win32 ID. Nothing is printed to stdout.
MESSAGE The message text to display.
TITLE Window title (default: "cshw").
TYPE Button and icon configuration, numeric or named.
Names may be combined with commas.
Type values:
0, ok OK button only
1, okcancel OK and Cancel buttons
2, abortretryignore
Abort, Retry, Ignore buttons
3, yesnocancel Yes, No, Cancel buttons
4, yesno Yes and No buttons
5, retrycancel Retry and Cancel buttons
Add for icons:
16, error Error icon (X)
32, question Question mark icon (?)
48, warning Warning icon (!)
64, info Information icon (i)
Also accepted: defbutton1, defbutton2, defbutton3, systemmodal,
taskmodal, topmost, and MB_-prefixed spellings.
msgbox "Hello World"
Simple message with OK button.
msgbox "Operation complete" "Status"
Message with custom title.
msgbox "Delete this file?" "Confirm" yesno
Yes/No confirmation dialog.
msgbox "File not found" "Error" 16
Error message with error icon.
msgbox "Are you sure?" "Confirm" 36
Yes/No (4) + Question icon (32).
msgbox "Are you sure?" "Confirm" yesno,question
The same thing, spelled out.
Returns the button clicked: 1 OK 2 Cancel 3 Abort 4 Retry 5 Ignore 6 Yes 7 No
Blocking: The shell waits for the user to click a button before continuing. This pauses script execution.
Return value: $result and $status both hold the button. Prefer $result -- $status is overwritten by the next command, and because it carries a button rather than success or failure, `msgbox ... || cmd` fires for every answer except OK:
msgbox "Continue?" "Confirm" yesno
if ($result == 6) then
echo "User clicked Yes"
endif
GUI Interaction: Message boxes appear in the foreground and grab focus. They work even when the shell is running in the background.
Scripting: Useful for user confirmations, error notifications, and interactive scripts that need user decisions. A script running unattended will stop at a msgbox until someone answers it.
messagebox, passworddlg, echo, read
mutex back to top ↑mutual-exclusion lock
mutex <name> create
mutex <name> lock
mutex <name> trylock [/timeout:ms]
mutex <name> unlock
mutex <name> status
mutex <name> destroy
A named mutual-exclusion lock, shared across coroutines and worker threads by name. You must create it before use; lock/unlock/trylock/status on an unknown name is an error (this catches typos instead of quietly auto-creating). unlock is owner-checked -- unlocking a mutex you do not hold is a reported error, not undefined behavior. Names live in the process-wide sync table; list them with `sync list mutex` and remove them with destroy or `sync destroy`.
create Create the mutex (idempotent).
lock Acquire, blocking until it is available.
FATAL ON FAILURE -- see below.
trylock [/timeout:ms]
Try to acquire; $? = 0 acquired, 1 busy. With
/timeout:ms, wait up to that long before giving up.
Never fatal: this is the verb for "tell me whether
I can have it".
unlock Release; error if not held by this thread.
status Show locked/unlocked and the owner thread id.
destroy Remove the mutex.
.WHY LOCK IS FATAL
A failed acquire followed by the critical section is data corruption, and it is
not the script's judgement call to make -- you cannot be past an acquire without
holding the lock. `mutex lock` used to report the failure, set $status, and fall
through to the very code it had failed to protect:
mutex counter_lock lock <- failed, printed an error
...critical section... <- ran anyway, unprotected
so a misspelled lock name gave every coroutine free rein over the shared state
with no symptom other than wrong answers. `lock` now stops the script (or the
coroutine, leaving the others and the shell alone). Nothing is lost: `trylock`
already existed for the case where not getting the lock is an outcome you mean
to handle, and it now carries /timeout: so a bounded wait is still available.
mutex m create
mutex m lock
# ... critical section ...
mutex m unlock
0 Operation succeeded (trylock: acquired). >0 Lock timeout, unlock not-owned, unknown name, or bad usage.
mv back to top ↑move or rename files and directories
mv [OPTION]... SOURCE DEST
mv [OPTION]... SOURCE... DIRECTORY
mv [OPTION]... -t DIRECTORY SOURCE...
Aliases: rename, move
Moves SOURCE to DEST, or moves several SOURCEs into DIRECTORY. Moving and renaming are the same operation: a rename is a move whose destination happens to be in the same directory.
On one volume a move only rewrites a directory entry, so even a very large file moves instantly. Across volumes the data has to be copied and the original removed, which mv does for you unless --no-copy says not to.
Overwrite policy:
-f, --force, /y Overwrite without asking. This is the default.
-i, --interactive Ask before overwriting an existing destination.
-n, --no-clobber Never overwrite; leave the destination alone.
If more than one of these is given, THE LAST ONE WINS -- which is
how GNU mv resolves it, so an alias carrying -i can still be
overridden by a trailing -f on the command line.
Backups:
-b Back up an existing destination before it is
overwritten. Simple backup, unless
VERSION_CONTROL says otherwise.
--backup[=CONTROL] Back up, choosing the scheme:
none, off no backups
numbered, t file.~1~, file.~2~, ...
existing, nil numbered if numbered
backups already exist,
otherwise simple
simple, never one backup, file~
-S, --suffix=SUF Suffix for a simple backup. Default "~", or
SIMPLE_BACKUP_SUFFIX from the environment.
Targets:
-t, --target-directory=DIR
Move every SOURCE into DIR. Useful when the
sources come from a glob, which would otherwise
have to leave the directory last.
-T, --no-target-directory
Treat DEST as an ordinary file even if a
directory of that name exists. Exactly one
SOURCE is allowed.
--strip-trailing-slashes
Drop trailing slashes from each SOURCE.
Other:
-u, --update Move only when SOURCE is newer than the
destination, or the destination is missing.
-v, --verbose Say what was moved, skipped, or backed up.
Windows move modes:
--write-through Do not return until the move is on the disk.
--no-copy Refuse a cross-volume move rather than falling
back to copy-and-delete.
--delay, --delay-until-reboot
Schedule the move for the next boot. This is how
a file something else has open gets replaced. It
is recorded in the registry, needs administrator
rights, and cannot copy across volumes.
--hardlink Move by creating a second name for the same data
and removing the first. Same volume only.
--fail-if-not-trackable
Fail rather than move a file the link-tracking
service cannot follow.
mv old.txt new.txt
Rename.
mv file.txt Documents\
Move a file into an existing directory.
mv project\ archived\project\
Move a whole directory. A trailing slash on a destination that
does NOT exist names the destination itself, so this renames
project to archived\project rather than trying to create
archived\project\project.
mv "My File.doc" "Renamed File.doc"
Names with spaces need quoting, as everywhere else.
mv *.log archive/
Move many files into a directory.
mv -t archive/ *.log
The same, with the directory named first.
mv -i important.conf C:\etc\
Ask before clobbering.
mv -b -S .orig config.ini C:\srv\config.ini
Keep the old destination as C:\srv\config.ini.orig.
mv --backup=numbered report.pdf C:\reports\
Keep every previous version: report.pdf.~1~, ~2~, ...
mv -u -v build\*.dll dist\
Refresh only what changed, and say what moved.
mv --delay locked.dll "C:\Program Files\App\locked.dll"
Replace a DLL that is currently loaded; it lands on next boot.
0 Every requested move was performed, or correctly skipped 1 At least one move failed
A move that -n or -u declined to perform is the requested outcome, not a failure, and does not set a non-zero status.
Every one of the overwrite flags used to be inert.
mv passed MOVEFILE_REPLACE_EXISTING unconditionally and read no switches at all, so -i never asked and -n overwrote the very file it exists to protect -- while reporting success. Both were documented here and recommended in the book. A script relying on the old behaviour was relying on mv ignoring what it was told.
MOVEFILE_CREATE_HARDLINK is reserved by Windows and does nothing at all, so --hardlink is implemented directly with CreateHardLink plus removal of the source name, which is what the flag was always meant to mean.
Cross-drive moves copy and then delete, so they are slower than a move within one volume and are not atomic.
nice back to top ↑run command with modified priority
nice COMMAND [ARGS...]
nice -n ADJUSTMENT COMMAND
Runs a command with adjusted scheduling priority. Lower priority allows other processes to get more CPU time, useful for background tasks.
COMMAND Command to run.
-n ADJUSTMENT Priority adjustment (-20 to 19, default: 10).
Positive = lower priority (nicer)
Negative = higher priority (requires admin)
Windows priority mapping:
-20 to -10 High priority
-9 to 0 Above normal
1 to 9 Normal
10 to 14 Below normal
15 to 19 Idle/Low priority
nice compress.exe largefile
Run compression at lower priority.
nice -n 15 backup.bat
Run backup at very low priority.
nice -n -5 important.exe
Run at higher priority (needs admin).
nice -n 19 longprocess.exe
Run at lowest priority (idle).
Returns the exit code of the command.
CPU Scheduling: Nice processes still run, just with lower priority. They get CPU time when higher-priority processes don't need it.
Negative Values: Increasing priority (negative nice) typically requires Administrator privileges on Windows.
Windows Priorities: Windows has fewer priority levels than UNIX. Nice values are mapped to the closest Windows priority class.
Background Tasks: Use nice for: - Backups - File compression - Large builds - Any task that shouldn't slow foreground work
Real-Time Priority: Extremely high priorities can make the system unresponsive. Use with caution.
nl back to top ↑number the lines of a file
nl [OPTIONS] [FILE...]
Writes each line of FILE to standard output with a line number in front of it. With no FILE, or when FILE is absent, reads standard input, so nl is usable in the middle of a pipeline.
By default only NON-BLANK lines are numbered; blank lines are printed with the number column left empty. That is the behaviour scripts expect, and it is why `nl` and `cat -n` differ.
-b STYLE Which body lines to number:
a every line, blank ones included
t non-blank lines only (the default)
n no lines at all
-w N Width of the number field. Default 6.
-s STR Separator printed after the number. Default is a TAB.
-v N Number of the first line. Default 1.
-i N Increment between line numbers. Default 1.
nl notes.txt
# 1<TAB>first line
# 2<TAB>second line
nl -ba notes.txt
Number blank lines too.
nl -w3 -s': ' notes.txt
# 1: first line
nl -v100 -i10 notes.txt
Start at 100 and count in tens.
grep ERROR log.txt | nl
Number the matches.
0 Success 1 A named file could not be opened
Why this is a built-in: pr, fold, fmt and nl were the last commonly-scripted Unix text tools cshw did not provide. On a machine with Git for Windows installed they appeared to work, because Git ships its own nl.exe and puts it on PATH -- so a script using nl ran here and failed on a clean Windows box, and the test suite could not tell the difference. They are built in now, so behaviour no longer depends on what else happens to be installed.
nohup back to top ↑run command immune to hangups
nohup COMMAND [ARGS...]
Runs a command that will continue running even if the shell is closed or the user logs out. Output is redirected to nohup.out if not already redirected.
COMMAND Command to run.
ARGS Arguments for the command.
nohup longprocess.exe
Run process that survives shell exit.
nohup backup.bat &
Background nohup process.
nohup script.bat > output.log 2>&1 &
Nohup with explicit output redirection.
nohup server.exe &
Start server that persists after logout.
Returns immediately if backgrounded, otherwise returns command's exit code.
Output: If stdout is a terminal, output redirects to nohup.out in the current directory (or $HOME/nohup.out if that fails).
Combination with &: nohup is typically combined with & to run in background: nohup command &
Signals: nohup makes the process ignore SIGHUP (hangup signal), which is sent when the terminal closes.
Use Cases: - Long-running server processes - Batch jobs that take hours - Processes that should survive logout
Windows Equivalent: On Windows, this is similar to starting a process detached from the console, allowing it to continue after shell exit.
Checking Status: Use 'processlist' or Task Manager to check if the process is still running.
nop back to top ↑no operation (alias for true)
nop
Does nothing; succeeds with $status = 0. Aliased at the dispatcher to `true`. Documented alongside `true` and `false` on a single page -- see `man true` for full details.
notify back to top ↑enable job completion notifications
notify
notify %JOBID
Enables or displays asynchronous notification when background jobs complete. When enabled, the shell immediately displays a message when a job finishes, rather than waiting until the next prompt.
(no args) Show notification settings.
%JOBID Enable notification for specific job.
notify %1
Enable notification for job 1.
longprocess &
notify %1
Start background job and enable notification.
# When job completes:
# [1] Done longprocess
0 Success 1 No such job
Default Behavior: By default, job completion is reported at the next prompt. With notify, you're informed immediately.
Use Cases: - Long-running background tasks - Multiple background jobs - When you need to know completion time precisely
Notification Format: [JOB#] Status Command Example: [1] Done backup.bat
Per-Job Setting: notify is set per job. Enable for jobs where you want immediate notification.
onintr back to top ↑set interrupt handler
onintr
onintr LABEL
onintr -
Specifies what happens when an interrupt signal (Ctrl+C) is received. Can ignore interrupts, handle them with a label, or restore default behavior.
(no args) Restore default interrupt handling.
LABEL Jump to LABEL when interrupted.
- Ignore interrupts (disable Ctrl+C).
onintr cleanup
# ... code that might be interrupted ...
exit 0
cleanup:
echo "Cleaning up..."
rm -f temp_*
exit 1
# When Ctrl+C pressed, jumps to 'cleanup'
onintr -
# Critical section - ignore interrupts
important_operation
onintr
# Restore normal interrupt handling
0 Success
Use Cases: - Clean up temporary files on interrupt - Save state before exiting - Prevent interruption during critical operations
Label Handling: When interrupted, the shell jumps to the specified label and continues execution from there.
Nested Handlers: Save and restore handlers for nested operations: onintr outer_handler # ... code ... onintr inner_handler # ... critical code ... onintr outer_handler # ... more code ...
Critical Sections: Use 'onintr -' to prevent interruption during operations that must complete atomically.
exit, trap
password back to top ↑read a password from the console (no echo)
password [/prompt:<text>] [/confirm]
Reads a line of input from the console with echo suppressed and stores it in $result. The console-mode counterpart of `passworddlg`. Suitable for scripts that need a password and are running without a GUI (over SSH, in CI, etc.).
/prompt:<text>
Prompt string. Default: "Password: ".
/confirm
Prompt twice and only return success if both entries match.
password
Read a password silently. $result holds the value.
password /prompt:"SSH passphrase: "
Custom prompt text.
password /confirm
Read twice, must match. Useful for setting a new password.
0 Password read successfully. 1 User cancelled (Ctrl-C), or /confirm fields differ.
Echo is suppressed via the console mode flags; only newline / backspace appear visibly while the user is typing.
passworddlg back to top ↑prompt for a password using a modal dialog
passworddlg [/title:<text>] [/prompt:<text>] [/confirm]
Shows a modal password-entry dialog and stores the entered password in $result. With /confirm, presents a second edit field and only returns success when both fields match.
The dialog runs on the UI thread (with fallback to a calling-thread modal pump in non-interactive mode) and routes activation correctly so the first edit field gets focus on open.
/title:<text>
Window title. Default: "Password".
/prompt:<text>
Prompt label above the edit field. Default: "Enter password:".
/confirm
Add a second edit field and require both entries to match.
passworddlg
Simple password prompt. $result has the password on OK.
passworddlg /title:"Backup" /prompt:"Backup passphrase:"
Custom title and prompt.
passworddlg /confirm /prompt:"New password:"
Two-field confirm form. Fails if the two fields don't match.
0 User clicked OK; $result holds the password. 1 User cancelled, or /confirm fields didn't match.
$result is set even on cancel (to an empty string) -- check $status to distinguish OK from cancel rather than testing $result for empty.
The console-mode equivalent (no GUI) is the `password` command.
pathmap back to top ↑map Unix-style paths to Windows destinations
pathmap add <unix> <win> [<win> ...]
pathmap del <unix>
pathmap list
pathmap clear
Maps Unix-style path prefixes (`/tmp`, `/usr/local/bin`, `/home/$USER`) to Windows destinations. cshw consults this table for any path argument that starts with `/`, BEFORE its built-in WSL / Cygwin / MSYS translations. An entry may list several destinations; they are tried in order and the first existing one wins.
Destination strings may contain %ENV% and $VAR references; they resolve at lookup time, not when the entry is added -- so a table that references $HOME stays correct across user accounts.
Defaults ship in <install>/pathmap.csh. To override per-user, create %APPDATA%/cshw/pathmap.csh; when present, cshw sources it instead of the shipped defaults during startup.
add <unix> <win> [win ...] Register a prefix mapping (multiple destinations
are tried in order; first-existing wins).
del <unix> Remove the entry for <unix>.
list Print all entries.
clear Drop every entry.
pathmap add /tmp %TEMP%
pathmap add /home/$USER %USERPROFILE%
pathmap list
0 Subcommand succeeded. >0 Bad usage / unknown subcommand.
peinfo back to top ↑display PE file information
peinfo FILE
peinfo [options] FILE
Displays detailed information about Windows Portable Executable (PE) files, including EXE, DLL, SYS, and other PE formats. Shows headers, sections, imports, exports, and other metadata.
FILE PE file to analyze.
-h, --headers Show PE headers only.
-s, --sections Show section information.
-i, --imports Show imported functions.
-e, --exports Show exported functions.
-r, --resources Show resources.
-a, --all Show all information.
peinfo program.exe
Display basic PE information.
peinfo -a C:\Windows\System32\kernel32.dll
Full analysis of kernel32.
peinfo -i malware.exe
Show imports (useful for analysis).
peinfo -e library.dll
Show exported functions.
peinfo -s driver.sys
Show section layout.
0 Success 1 File not found 2 Not a valid PE file
Information Displayed: - Machine type (x86, x64, ARM) - Subsystem (GUI, Console, Driver) - Entry point address - Section table (code, data, resources) - Import table (DLLs and functions used) - Export table (functions provided) - Timestamps, checksums
Security Analysis: peinfo is valuable for malware analysis: - Check imports for suspicious APIs - Examine section characteristics - Verify digital signatures - Detect packers/obfuscation
PE Format: The PE format is used by Windows executables, DLLs, drivers, and other binary files. Understanding PE structure helps with debugging and security analysis.
Packed Files: Packed/encrypted executables may show unusual characteristics: - Few imports - High entropy sections - Unusual section names
popd back to top ↑pop directory from stack and change to it
popd
Removes the top directory from the directory stack and changes to that directory. Used in conjunction with pushd to navigate back to previously saved locations.
pushd C:\Projects
# work in Projects...
popd
Return to the directory where pushd was issued.
pushd dir1
pushd dir2
popd
Return to dir1.
popd
Return to original directory.
0 Success 1 Directory stack is empty 2 Cannot change to directory (deleted or inaccessible)
Empty Stack: If the directory stack is empty, popd will display an error message. Use 'dirs' to check the stack contents.
Deleted Directories: If the directory on the stack no longer exists (was deleted while you were elsewhere), popd will fail.
postmessage back to top ↑post a Win32 message to a window's queue (async)
postmessage <hwnd> <msg> [<wParam> [<lParam>]]
Calls PostMessageW(hwnd, msg, wParam, lParam). The message is appended to the target window's thread message queue and the call returns immediately. $result is 1 on success, 0 on failure.
`msg` accepts the same symbolic-WM_* names and numeric forms as `sendmessage`.
<hwnd> Target HWND in hex or decimal. Must satisfy IsWindow().
<msg> Symbolic (WM_CLOSE, ...) or numeric.
<wParam> WPARAM. Default 0.
<lParam> LPARAM. Default 0.
# Fire-and-forget close request:
postmessage $w WM_CLOSE
# Post a custom WM_USER notification (plugins may translate this
# into a script-event via DispatchScriptEvent):
postmessage $w WM_USER 1 0
0 PostMessage returned TRUE; $result = 1.
1 PostMessage returned FALSE; $result = 0. Use $? for the
Windows error code.
Use `sendmessage` when the message handler needs to run BEFORE the script continues (e.g., the WM_CLOSE veto path). Use `postmessage` when you want the script to keep running without waiting.
pr back to top ↑paginate text for printing
pr [-t] [-n] [-h TEXT] [-l N] [FILE...]
Arranges text into pages for printing: a header on each page carrying the date, a title and a page number, optional line numbers, and padding so each page is a fixed number of lines. With no FILE, reads standard input.
pr is the formatting front end to the printing family: pr for layout, lp or lpr to send the result to a printer.
In scripts the most common form by far is `pr -t`, which drops the headers entirely and leaves pr as a plain filter.
-t Omit page headers and trailers, and the page padding.
Turns pr into a straight-through filter.
-n Number lines. Five columns, then a TAB.
-h TEXT Use TEXT as the page title instead of the file name.
-l N Page length in lines. Default 66, of which ten are the
header and trailer, leaving 56 lines of text.
pr report.txt
Paginate with the default header:
#
#
# 2026-08-01 04:00 report.txt Page 1
#
#
# ...text...
pr -t -n report.txt
No header, just numbered lines.
pr -h "Quarterly Summary" report.txt | lp
Custom title, sent to the printer.
grep ERROR log.txt | pr -h "Errors" -l 60 | lp
0 Success 1 A named file could not be opened
Not implemented -- multi-column output: The -2, -3, ... options that lay text out in columns are NOT supported. Passing one is an ERROR rather than a silent no-op, so a script that depends on columns fails where you can see it instead of quietly producing single-column output that looks nearly right.
Header format: Two blank lines, the header line, two more blank lines, then the text, then five blank lines. That is pr's traditional five-and-five layout, which is what makes -l 66 give 56 usable lines.
prename back to top ↑rename files with a Perl-style expression
prename [options] EXPRESSION FILE...
Applies a Perl-style expression to each FILE's name and renames the file to the result. Also installed as `file-rename`, which is the other name this tool ships under.
This is the third program called rename. Debian and Ubuntu shipped it as plain `rename` for years while Fedora shipped util-linux's, which is why a script written for one silently mangles filenames under the other. cshw gives each its own name so neither has to be guessed at: `rename` is cmd.exe's and util-linux's, and this is Perl's.
prename 's/\.htm$/.html/' *.htm prename 'y/A-Z/a-z/' *.TXT
Two expression forms are implemented natively:
s/PATTERN/REPLACEMENT/[gi] substitute y/FROM/TO/ transliterate, character for character
`tr/FROM/TO/` is accepted as a spelling of y///. Any non-alphanumeric character works as the delimiter, so s#/tmp/#/var/# needs no escaping.
PATTERN is a Perl-compatible regular expression, and REPLACEMENT uses Perl's capture syntax:
prename 's/v(\d+)/version$1/' v2.log -> version2.log
FROM and TO in y/// take ranges, and a shorter TO repeats its last character, both as tr does:
y/A-Z/a-z/ lower-case the name y/0-9// delete every digit y/xyz/#/ every x, y or z becomes #
-n, --no-act Change nothing, and print what would have
happened. Implies -v, as util-linux and
File::Rename both do: a dry run that says nothing
cannot be told apart from one that matched nothing,
and telling those apart is the whole point of
checking before a bulk rename that has no undo.
-o, --no-overwrite Skip a file whose new name is already taken.
-v, --verbose Print each rename as `old' -> `new'.
--perl Hand the expression to a real Perl interpreter
instead of running it here. See NOTES.
prename 's/\.jpeg$/.jpg/' *.jpeg
The everyday case.
prename -n 's/^IMG_/photo_/' IMG_*.jpg
Show what a batch WOULD do and change nothing. Worth doing first;
a bulk rename has no undo.
prename 's/(\d{4})-(\d{2})-(\d{2})/$3-$2-$1/' 2026-08-02-notes.txt
Reorder a date with captures: 02-08-2026-notes.txt
prename 'y/ /_/' *.txt
Spaces to underscores.
prename --perl 's/\d+/$&*2/e' file1.txt
An expression this does not implement, run by Perl itself.
0 Every file that matched was renamed. 1 At least one rename failed. 2 The expression or the command line was unusable.
A name the expression does not change is not an error. It is simply a file the expression did not select, and it is passed over in silence.
The name only, never the path: The expression is applied to the FILE NAME and not to the directory leading to it, so `prename 's/a/b/' sub\aaa.txt` renames aaa.txt inside sub and leaves sub alone. A renamer that can silently relocate a file is not doing the job its name promises.
--perl, and why it is not automatic: Real perl-rename evals arbitrary Perl. This implements s/// and y///, which is what essentially all use of it looks like, and PCRE2 is Perl-compatible for exactly that syntax. For anything beyond it, --perl hands the whole expression to an interpreter.
That is opt-in, and deliberately so. prename NEVER delegates because Perl happens to be installed: it fails identically on every machine without --perl, so a script that works at one desk works at the next. An ambient fallback would make the same command behave differently depending on what else was installed -- the exact problem that made pr, fold, fmt and nl built-ins instead of leaning on Git's.
Detection informs the MESSAGE, never the behaviour. When an expression falls outside the subset, the error says whether Perl is on PATH, present but not on PATH, or absent -- and what to type either way. All three still require --perl.
Where it looks: PATH first, then C:\Strawberry\perl\bin, Git's usr\bin and msys64\usr\bin. Git for Windows ships a perl and keeps it off the system PATH, so "is Perl installed" and "is perl on PATH" are different questions and this answers both. When --perl runs, it reports which interpreter it used.
https://strawberryperl.com is the usual Windows Perl: it installs to C:\Strawberry, puts perl on PATH, and bundles a compiler, so CPAN modules build the way they do on Linux.
printenv back to top ↑print environment variables
printenv
printenv NAME
printenv NAME...
Prints the values of environment variables. Without arguments, prints all variables. With arguments, prints only the specified variables.
NAME Specific variable(s) to print.
printenv
Print all environment variables.
printenv PATH
Print only PATH variable.
printenv PATH HOME TEMP
Print multiple variables.
printenv USERNAME
Print current username.
printenv NONEXISTENT
# Outputs nothing (no error)
0 Success (variable found or all printed) 1 Variable not found (when specific name given)
Output Format: When printing a specific variable, only the value is shown (no NAME=). When printing all, format is NAME=VALUE.
Scripts: Useful in scripts to get environment values: set mypath=$(printenv PATH)
Comparison: - printenv NAME: Prints value only - echo %NAME%: Also prints value (Windows syntax) - env: Prints NAME=VALUE format
printf back to top ↑format and print arguments
printf <format> [argument ...]
Print the arguments under the control of <format>, in the style of the C printf function. Unlike echo, printf adds no trailing newline -- the format string controls the output exactly.
The format string may contain:
Literal text, printed as-is.
Backslash escapes: \n \t \r \a \b \f \v \\
Conversion specifications, each introduced by % and consuming one argument: %s string %d %i signed integer %u %o %x %X unsigned, octal, lower/upper hexadecimal %c the first character of the argument %f %e %E %g %G floating point %% a literal percent sign Flags (- + space # 0), a field width, and a .precision may appear between the % and the conversion -- e.g. %-10s, %05d, %.2f.
If there are more arguments than the format consumes, the format is reused until every argument has been printed. Missing arguments are treated as an empty string or zero.
printf '%s\n' hello
Prints hello, followed by a newline.
printf '%-8s%5d\n' item 42
Prints the name left-justified in 8 columns, the number in 5.
printf '%.2f\n' 3.14159
Prints: 3.14
printf '%s\n' a b c
Prints a, b and c on three lines -- the format is reused.
Zero on success. printf with no format argument is a usage error.
processlist back to top ↑list running processes
processlist
processlist [options]
ps
Displays a list of all processes currently running on the system. Shows process ID (PID), parent process ID (PPID), process name, thread count, and memory usage.
This command is essential for system monitoring, finding process IDs for the kill command, and identifying resource-heavy processes.
/v, --verbose Show additional details including module path.
/s, --sort NAME Sort by: name, pid, memory, threads.
/f, --filter Filter by process name pattern.
processlist
List all running processes.
processlist /v
Verbose listing with full paths.
processlist | grep chrome
Find Chrome-related processes.
processlist /s memory
Sort processes by memory usage.
0 Success
Information Displayed: - PID: Process ID (unique identifier) - PPID: Parent Process ID (who started this process) - Name: Executable name - Threads: Number of threads in the process - Memory: Working set size (RAM usage)
Administrator Privileges: Some system processes may show limited information unless running as Administrator.
Process Relationships: The PPID column shows parent-child relationships between processes. A process with PPID 0 is typically a system process.
Performance: On systems with many processes, the command may take a moment to enumerate all processes.
progressdlg back to top ↑show and drive a modeless progress dialog
progressdlg <subcommand> [args]
Shows a modeless progress-bar dialog and updates its state from the script. The first state-modifying subcommand creates the dialog; `progressdlg end` dismisses it.
Bound click handlers fire as coroutines, so the UI thread stays responsive. Out-of-range positions / increments are clamped to the current range rather than wrapping or erroring.
setcaption <text>
Set the window title.
setstatus <text>
Set the status line below the progress bar (e.g. "12 of 100").
setbarrange <min> <max>
Set the bar's range. Current position clamps into the new range.
setbarpos <n>
Jump to an absolute position. Clamped to [min, max].
incrementbar [<n>]
Add n to the position (default +1; negative ok; clamped).
button <text>
Set the button label AND make the button visible.
showbutton YES|NO
Show or hide the button. `showbutton:YES` colon form also accepted.
onbuttonclick <proc>
Bind a script proc to the button click. The proc fires on a
coroutine thread; the UI thread is not blocked.
onbuttonclick cancel
Shortcut: clicking the button destroys the dialog.
`onbuttonclick:cancel` colon form also accepted.
hide
ShowWindow SW_HIDE -- the window is hidden but state is kept.
show
ShowWindow SW_SHOW. Creates the dialog if it doesn't exist yet.
gethwnd
Set $result to the dialog's HWND (0x0 when none is showing).
end
Destroy the dialog.
progressdlg setcaption "Downloading..."
progressdlg setbarrange 0 100
progressdlg button "Cancel"
progressdlg onbuttonclick:cancel
foreach i (0 1 2 3 4 5 6 7 8 9)
progressdlg setstatus "${i}0 of 100"
progressdlg incrementbar 10
sleep 0.5
end
progressdlg end
# Bind a custom click handler instead of just dismissing:
proc on_cancel
share user_cancelled = 1
progressdlg end
endproc
progressdlg button "Stop"
progressdlg onbuttonclick on_cancel
0 Success. 1 Bad subcommand, parse error, or UI thread unavailable.
Only one progress dialog exists at a time. Calling state-modifying subcommands without an existing dialog auto-creates it; subsequent calls update the live dialog via SendMessage so script-side updates from any thread are safe.
Bound click procs run as coroutines (CShellCoroutineManager). They can call back into progressdlg (e.g., setstatus) from inside the proc without deadlocking the UI thread.
prompt back to top ↑set or display command prompt
prompt
prompt FORMAT
Sets or displays the shell command prompt. The prompt appears before each command you enter, typically showing the current directory and other useful information.
FORMAT Prompt format string with special codes.
Special codes:
$P Current directory path
$G Greater-than sign (>)
$L Less-than sign (<)
$N Current drive letter
$D Current date
$T Current time
$S Space
$$ Dollar sign
$Q Equals sign (=)
$H Backspace
$E Escape character
$_ Newline
prompt
Display current prompt format.
prompt $P$G
Standard prompt: "C:\Users\Me>"
prompt [$T] $P$G
Add time: "[14:30:25] C:\Users\Me>"
prompt $N:$G
Drive letter only: "C:>"
prompt $P$_$G
Directory on one line, > on next.
prompt cshw $P$G
Add prefix: "cshw C:\Users\Me>"
prompt [$D $T]$_$P$G
Date/time on first line, path on second.
0 Success
Default Prompt: The default prompt is typically "$P$G" showing the current path followed by ">".
Customization: The prompt can include any text along with special codes. Use $_ for multi-line prompts.
Colors: Color codes may be supported using ANSI escape sequences with $E.
Persistence: Prompt settings are not saved between sessions. Add your prompt command to your startup script for persistence.
ps back to top ↑Lists all the processes running on the system (alias for processlist).
No detailed man page yet — see the one-line summary above.
pushd back to top ↑push directory onto stack and change to it
pushd DIRECTORY
pushd
Saves the current directory on a stack and then changes to the specified directory. This allows you to easily return to your previous location using popd.
The directory stack enables efficient navigation between multiple working directories without losing track of where you've been.
DIRECTORY The directory to change to.
Without arguments, pushd swaps the top two directories on the stack.
pushd C:\Projects
Save current directory and change to C:\Projects.
pushd src
Save current directory and change to src subdirectory.
pushd
Swap current directory with top of stack.
pushd D:\Backup
# ... do work in D:\Backup ...
popd
Return to original directory.
0 Success 1 Directory not found 2 Invalid argument
$dirstack: The stack is also a variable. $dirstack[1] is the CURRENT directory and deeper indices are the pushd stack with the most recently pushed first, which is both the order `dirs` prints and the order tcsh uses. It moves with `cd` as well as with pushd and popd, and `dirs -c` leaves it holding just the current directory.
pushd libs echo "came from $dirstack[2]"
$dirstack was always empty before, so a script could read the text `dirs` prints but had no way to get at an entry.
Stack Operations: - pushd adds to the stack and changes directory - popd removes from the stack and changes back - dirs shows the current stack
Multiple Pushes: You can push multiple directories onto the stack: pushd dir1 pushd dir2 pushd dir3 # Now stack has 3 entries
The most recent push is at the top and will be the first restored by popd.
Use Cases: - Temporarily work in another directory - Navigate between related project directories - Keep track of multiple working locations
pwd back to top ↑print working directory
pwd
Prints the absolute path of the current working directory. This is the directory where relative paths are resolved from and where commands operate by default.
pwd
Display current directory path.
set currentdir=$(pwd)
Store current directory in a variable.
0 Success (always)
The current directory is also available in the $: special variable: echo $:
pwd is equivalent to 'cd' with no arguments.
quicsrv back to top ↑launch and supervise quicsrv QUIC/UDP (HTTP/3) server worker processes
quicsrv start <port> [/dllcfg:<file>] [/norestart]
quicsrv status <id>
quicsrv stop <id>
quicsrv list
The UDP/QUIC sibling of tsrvd. quicsrv runs a QUIC server in a SEPARATE process (quicsrv.exe), with cshw as the master over the same control-pipe supervision (launch, status, stop, auto-restart). QUIC runs over UDP, a different transport from tsrvd's TCP, so it is a separate command and worker. It is the foundation for HTTP/3.
Given a document root in its config, quicsrv serves HTTP/3 through the SAME static-file + CGI engine that backs http.dll's HTTP/1.1 and HTTP/2 -- a site or a CGI API behaves identically over h1, h2, and h3. Without a root it runs a minimal QUIC echo (a transport self-test).
quicsrv.exe is found next to cshw.exe. The server certificate and document root come from the /dllcfg file.
start <port> [/dllcfg:<file>] [/norestart]
Launch a QUIC worker listening on UDP <port>. /dllcfg supplies the config
(TLS cert + optional document root / CGI). Blocks until the worker is up;
sets $result to the new daemon id. A worker that dies unexpectedly is
auto-restarted (with backoff); /norestart opts out.
status <id>
Query the worker and print its STAT line:
STAT <accepted> <active> <running>
(connections accepted, currently active, and 1 if listening). Also sets
$result to that line.
stop <id>
Ask the worker to stop; if it overstays it is terminated. Removes it from
the list.
list
Show all workers: id, port, pid, state (running/dead/failed), restart
count (RST), and the last STAT seen.
The /dllcfg file is key=value (# / ; comments; optional quotes on values):
tlscert server cert: a .pfx path, or a Windows-store subject / SHA1 thumbprint
tlspfxpass password if tlscert is a .pfx
tlsstore store name if tlscert is a store cert (default MY)
root document root to serve over HTTP/3 (its presence enables h3 mode)
index default file(s) for a directory request (default: index.html index.htm)
listing on = auto directory index when there is no index file
cgiprefix URL prefix routed to CGI scripts (e.g. /api/)
cgidir directory of CGI scripts
cgiexe CGI interpreter (default: cshw.exe next to quicsrv.exe)
Example -- serve a site plus an API over HTTP/3 on UDP 443:
# site.conf
tlscert = C:\certs\server.pfx
tlspfxpass = changeme
root = C:\www
cgiprefix = /api/
cgidir = C:\www\api
quicsrv start 443 /dllcfg:site.conf
Clients reach HTTP/3 after first seeing an Alt-Svc header over HTTP/1.1 or HTTP/2. Set `altsvc` in the http.dll config (see Chapter 19) so its responses advertise the quicsrv endpoint and browsers upgrade to h3. .AUTO-RESTART A worker that exits unexpectedly is relaunched automatically, with increasing backoff. If it crash-loops it is marked 'failed' and left alone (visible in `quicsrv list`); `quicsrv stop <id>` clears it. /norestart on `start` opts out.
HTTP/3 uses vendored msquic (the QUIC transport, the same one Windows' HTTP.sys uses) plus nghttp3 (framing + QPACK), shipped alongside quicsrv.exe. QUIC is UDP/443, which some locked-down networks block; clients that cannot reach h3 fall back to h2/h1.1, which is expected.
If cshw exits, the control pipe closes and the worker detects the master is gone and stops itself -- so workers are not orphaned.
0 Success >0 Error (worker not found, failed to launch, no cert configured, etc.)
rcl back to top ↑register command library (load plugin DLL)
rcl PATH
rcl PATH PREFIX
rcl PATH PREFIX /prefixonly
registercmdlib PATH [PREFIX] [/prefixonly]
Loads a command library DLL and registers its commands with the shell. Command libraries are DLL plugins that extend cshw with custom commands.
The DLL must export a RegisterCommandLibrary function that returns command definitions. Each command includes init, execute, and help functions following the CSHW plugin API.
Commands can be accessed with or without the namespace prefix: mylib:mycmd Explicit namespace (always works) mycmd Direct access (if no conflict)
Plugins can shadow intrinsic commands. When a plugin command has the same name as a built-in command, the plugin version takes precedence. The original command is restored when the library is unloaded.
PATH Path to the DLL containing command definitions.
PREFIX Optional namespace prefix for commands.
/prefixonly Commands only accessible with prefix.
/p Short form of /prefixonly.
rcl C:\Plugins\mylib.dll
Load plugin with auto-detected prefix.
rcl C:\Plugins\mylib.dll tools
Load plugin with "tools" prefix.
Commands available as: tools:cmd or cmd
rcl C:\Plugins\mylib.dll tools /prefixonly
Load with prefix required.
Commands only available as: tools:cmd
rcl "C:\Program Files\MyApp\plugin.dll" myapp
Load plugin with spaces in path.
0 Success 1 DLL not found 2 Invalid plugin format (missing RegisterCommandLibrary) 3 API version mismatch 4 Registration failed 5 Command conflicts with existing plugin command
Command libraries can be preloaded automatically from:
INI File (cshw.ini next to cshw.exe):
[CommandLibraries]
C:\Plugins\mylib.dll=mylib
C:\Plugins\tools.dll=tools:prefixonly
Registry:
HKEY_CURRENT_USER\Software\cshw\CommandLibraries
Value name: DLL path
Value data: prefix
Environment Variable:
CSHW_CMDLIBS=C:\lib1.dll;C:\lib2.dll:prefix2
Plugin DLLs must export these functions:
BOOL RegisterCommandLibrary(CShwPluginLibraryInfo** ppInfo)
Called when plugin is loaded. Returns library info and
command definitions.
void UnregisterCommandLibrary(void)
Called when plugin is unloaded. Perform cleanup here.
See CShellPluginAPI.h for the complete API specification.
Plugin Development: Include CShellPluginAPI.h from the cshw SDK to develop plugins. The header contains structures, typedefs, and convenience macros.
Shadowing: Plugins can override built-in commands with a warning. This allows extending or replacing default behavior. Originals are restored when the library is unloaded.
Security: Only load DLLs you trust. Plugin DLLs have full access to the shell process and can execute arbitrary code.
Architecture: 32-bit plugins require 32-bit cshw. 64-bit plugins require 64-bit cshw.
rd back to top ↑remove a directory (alias for rmdir)
rd <directory>
`rd` is identical to `rmdir`. See `man rmdir` for full documentation.
readfile back to top ↑read a file's contents into a shell variable
readfile <variable> <file>
readfile reads the entire contents of <file> and stores them in the shell variable <variable>.
It is the direct way to get a file into a variable. The csh idiom `set v = \`cat file\`` also works, but backtick substitution strips the file's trailing newline and spawns a command; readfile keeps the exact content (trailing newline included) and runs in-process.
The file is read as text -- CRLF line endings are normalized to LF. For binary files, use fileblob instead.
readfile notes settings.txt
Load settings.txt into $notes.
readfile body message.txt
echo "$body"
0 on success; non-zero if the file cannot be opened.
readonly back to top ↑make a variable read-only
readonly <name> [= <value>]
readonly <name1> <name2> ... <nameN>
Marks one or more variables as read-only. Once a variable is read-only, further `set` / `share` / `unset` attempts against it fail with a diagnostic and a non-zero $status. The variable's value can still be read normally.
The read-only flag is per-variable, not per-namespace -- a local read-only variable disappears when its proc returns, freeing the name for re-use at the next outer scope.
<name> Variable name(s) to mark read-only.
<value> Optional value to assign at the same time (only when
one name is given).
readonly MAX_RETRIES = 5
set MAX_RETRIES = 99
# ERROR: MAX_RETRIES is read-only
readonly version = "1.0.0-alpha.1"
echo "running $version"
proc enforce_constants
readonly tax_rate = 0.07
# ...calculations using $tax_rate...
# tax_rate disappears (and is re-assignable) when this proc returns.
endproc
0 Variable(s) marked read-only.
1 Variable not found, or already read-only with a conflicting
re-declaration.
Once set, the read-only flag cannot be removed in this session. The intent is to lock down constants and configuration values that the rest of the script must treat as invariants.
realpath back to top ↑print the absolute, canonical form of a path
realpath <path>
Print <path> in absolute, canonical form. "." and ".." components are resolved, and a relative path is made absolute against the current working directory. Forward slashes are normalized to backslashes.
realpath is a pure path computation -- it does not consult the filesystem and <path> does not need to exist. This makes it safe for building up paths that you are about to create.
realpath .
Prints the current working directory.
realpath ..
Prints the parent of the current directory.
realpath a/b/../c
Prints <cwd>\a\c -- the ".." cancels "b".
Zero on success. realpath with no path argument is a usage error; a non-zero status is also returned if the path cannot be resolved.
registercmdlib back to top ↑register command library (load plugin DLL)
registercmdlib PATH [PREFIX] [/prefixonly]
rcl PATH [PREFIX] [/prefixonly]
Alias for rcl. See 'man rcl' for full documentation.
registry back to top ↑in-shell Windows Registry operations
registry <op> KEY [options]
Native Windows Registry access from cshw scripts. Named `registry` rather than `reg` so the system reg.exe stays reachable from cshw via PATH lookup. Switch syntax uses CSHW's colon form (e.g., `/v:NAME`) rather than reg.exe's space-separated form. Both `--long-form` and `-short` switches are accepted.
Operations:
query KEY [/v:VALUE] [/s] [/q]
Display values and subkeys. /v: limits to one value;
/s recurses; /q makes a missing key a silent zero-result
success.
get KEY /v:VALUE [/q]
Pipe-friendly read -- prints just the data, no header or
type column. Suitable for `set foo = `registry get ...``.
list KEY [/q] (alias: ls)
Print just the subkey names, one per line. Lighter than
tree, more focused than query for foreach loops.
add KEY /v:VALUE /t:TYPE /d:DATA [/f] [/idempotent]
Create the key if missing and set VALUE. Repeat /d: for
REG_MULTI_SZ lines. /f skips overwrite confirmation.
delete KEY [/v:VALUE] [/f]
Delete a value (with /v:) or the entire key (without).
copy SRCKEY DSTKEY [/s] [/f]
Copy a key (and optionally subkeys) to another path.
tree KEY [/q]
Recursively print the subkey tree under KEY.
export KEY FILE [/q]
Write the subtree to a .reg file.
import FILE [/f]
Apply a .reg file to the registry.
Key prefixes:
HKLM\... | HKEY_LOCAL_MACHINE\...
HKCU\... | HKEY_CURRENT_USER\...
HKCR\... | HKEY_CLASSES_ROOT\...
HKU\... | HKEY_USERS\...
Common types for /t:
REG_SZ, REG_EXPAND_SZ, REG_MULTI_SZ, REG_DWORD, REG_QWORD,
REG_BINARY, REG_NONE
registry query "HKLM\SOFTWARE\Tropibyte\cshw"
set ver = `registry get "HKLM\SOFTWARE\Tropibyte\cshw" /v:Version`
echo "installed cshw version: $ver"
registry add "HKCU\Software\Tropibyte\cshw" /v:Theme /t:REG_SZ /d:dark /f
registry list "HKLM\SOFTWARE\Tropibyte"
registry delete "HKCU\Software\Tropibyte\cshw" /v:Theme /f
registry export "HKLM\SOFTWARE\Tropibyte" cshw-config.reg
0 Operation succeeded (or /q used on a missing key). 1 Bad arguments or operation-specific failure (see stderr).
HKLM writes typically require admin. /q (--quiet) is useful in scripts to avoid noisy failures when a key is expected-not-present.
rehash back to top ↑rebuild command lookup hash table
rehash
Rebuilds the internal hash table that caches command locations. The shell maintains a hash of command names to paths for faster lookup. Use rehash after installing new programs to make them immediately available.
rehash
Rebuild command hash table.
# After installing a new program:
# 1. Install program (adds to PATH)
# 2. rehash
# 3. New program is now findable
0 Success
When to Use: Rehash is needed when: - New programs are installed to PATH directories - PATH is modified - Programs are added/removed from PATH directories
Automatic Rehash: The shell may rehash automatically in some cases, but explicit rehash ensures the cache is current.
Performance: The hash table makes command lookups faster by avoiding repeated PATH searches. rehash rebuilds this optimization.
Shell Compatibility: rehash is traditional in csh/tcsh. Other shells use different mechanisms (bash: hash -r).
rename back to top ↑rename a file, or substitute in many file names
rename OLD NEW
rename [options] FROM TO FILE...
Two commands answer to the name `rename` in the wild, and the number of operands says which one you meant. They cannot be confused: the first form is always exactly two words, and the second always needs at least three, because a substitution with no files to apply it to does nothing.
With TWO operands this is cmd.exe's rename, and it is `mv`. Every option mv accepts works here, and `man mv` documents them.
rename notes.txt notes.bak
With THREE OR MORE it is util-linux's rename(1): the first occurrence of FROM in each FILE's name is replaced by TO.
rename .txt .bak *.txt
These apply to the FROM TO FILE... form only. The two-operand form takes
mv's options instead.
-a, --all Replace every occurrence in a name, not just the
first.
-n, --no-act Change nothing, and print what would have
happened. Implies -v, as util-linux and
File::Rename both do: a dry run that says nothing
cannot be told apart from one that matched nothing,
and telling those apart is the whole point of
checking before a bulk rename that has no undo.
-o, --no-overwrite Skip a file whose new name is already taken,
rather than replacing it.
-v, --verbose Print each rename as `old' -> `new'.
rename report.doc report-final.doc
The everyday form. This is mv.
rename draft.txt archive\draft.txt
Renaming ACROSS directories, which cmd.exe refuses. See NOTES.
rename .txt .bak *.txt
one.txt two.txt -> one.bak two.bak
rename -v IMG_ photo_ IMG_*.jpg
Re-prefix a batch, reporting each one.
rename -a _ - my_long_file_name.txt
Every underscore, not just the first:
my-long-file-name.txt
rename -n -v .log .old *.log
Show what a batch WOULD do and change nothing. Worth doing first;
a bulk rename has no undo.
0 Every file that matched was renamed. 1 At least one rename failed. 2 The command line was unusable.
A file whose name does not contain FROM is not an error. It is simply a file the substitution did not select, and it is passed over in silence.
Renaming across directories: cmd.exe refuses this -- "you cannot specify a new drive or path for your destination file" -- and so does PowerShell's Rename-Item: "Cannot rename the specified target, because it represents a path or device name." cshw allows it, because MoveFileEx allows it: a move to another directory is a rename, and a move to another VOLUME is done as a copy followed by a delete rather than refused. Declining to do something the platform supports would not make the command safer, only less useful.
The substitution form is different: it rewrites the FILE NAME only and never the path leading to it, so `rename . _ sub\a.txt` renames a.txt inside sub and leaves sub alone. Substituting across the whole path is how the classic `rename . X *` accident scatters a directory, and a renamer that can silently relocate a file is not doing the job its name promises.
Which -n did you mean: The two forms come from different tools, and they disagree about one letter. In the two-operand form -n is mv's --no-clobber. In the substitution form it is util-linux's --no-act. The operand count has already decided which command you are running, so each -n means what it means in that command.
The third rename: A third program of this name exists on Linux -- perl-rename, also packaged as prename or file-rename -- which takes a Perl expression:
prename 's/\.htm$/.html/' *.htm
cshw implements it under those names. See `man prename`.
It deliberately does NOT answer to `rename`. Its shape is an expression plus files, which at three or more operands is the same shape as util-linux's FROM TO FILE..., so `rename s/a/b/ x.txt y.txt` is genuinely ambiguous -- util-linux reads it as "replace the literal text s/a/b/ with x.txt in the name y.txt". Operand count has already been spent telling cmd.exe's form from util-linux's and has nothing left to give.
Debian and Fedora historically shipped different programs under this one name, and a script written for one silently mangles names under the other. Giving each dialect its own name is how cshw avoids reproducing that.
mv, cp, copy, prename, file-rename
repeat back to top ↑run a command a given number of times
repeat count command [argument ...]
Run a single command, with its arguments, count times in the current shell. The count must be the first argument and must be an integer.
A count of zero or a negative number runs the command zero times -- a successful no-op.
repeat runs one command. It is not a loop construct: for anything needing a loop body of multiple statements, use while, foreach, or loop instead.
count
Integer number of repetitions.
command [argument ...]
The command to run, with any arguments.
repeat 3 echo hi
Prints "hi" three times.
repeat 5 mkdir -p scratch
Runs the mkdir five times (harmless after the first).
repeat 0 echo nope
Runs nothing; succeeds.
0 The count parsed and the command ran (or count <= 0). 1 Missing arguments, or the count is not a valid integer.
The command runs in the current shell, so state changes it makes persist between iterations and after repeat returns.
while, foreach, loop, eval
retproc back to top ↑return from the current procedure with a value
retproc [value]
Pops the current procedure frame and publishes [value] as $result in the calling scope -- the explicit "return from a proc" verb. It is an error to call retproc outside an enclosing `proc ... endproc` block.
Companion to retshell: use retproc to unwind exactly ONE proc (bubbling up if nested); use retshell to bail all the way out to the sourcing shell. `return` is the smart variant -- it pops a proc if you are in one, otherwise behaves like retshell.
proc square
@ r = $1 * $1
retproc $r
endproc
square 7
echo $result # 49
Does not return normally -- it unwinds the proc frame. Calling it outside a proc is an error.
retshell back to top ↑exit a sourced script without killing the shell
retshell [code]
Exits the current sourced script (or `cshw script.csh` subshell) with the given exit code (a numeric argument, default 0), WITHOUT terminating the calling interactive shell. Use it in cshrc or sourced setup scripts to bail on a missing precondition while keeping the user's session intact. A non-numeric argument is an error.
How the four "leave" verbs differ:
retshell : ALWAYS exits the script frame, never a proc.
retproc : ALWAYS pops a proc frame; errors outside one.
return : smart -- pops a proc if in one, otherwise the script.
exit : terminates the WHOLE shell -- fine for a `cshw script.csh`
subprocess, fatal inside a sourced file.
# in a sourced setup script:
if (! -f required.conf) then
echo "required.conf missing -- skipping setup"
retshell 1
endif
Does not return normally -- it unwinds the script frame with [code] (default 0).
rev back to top ↑reverse lines character by character
rev [FILE]
command | rev
Reverses the order of characters in each line. Reads from files or standard input, outputting each line with characters in reverse order.
FILE File to process (default: stdin).
echo "hello" | rev
Output: olleh
rev file.txt
Reverse each line in file.
echo "12345" | rev
Output: 54321
echo "Was it a car or a cat I saw" | rev
Reveal palindrome patterns.
dir /b | rev | sort | rev
Sort by reversed names (by extension effectively).
0 Success 1 File not found or read error
Line by Line: Each line is reversed independently. The order of lines is preserved.
Use Cases: - Checking palindromes - Reversing text for effects - Creative sorting tricks - Text manipulation puzzles
Unicode: Works with Unicode characters, reversing by character not by byte.
Comparison: - rev: Reverses characters within lines, leaving line order alone - tac: Reverses the order of lines, leaving each line alone Both exist here; `tac file | rev` does both.
rm back to top ↑remove files
rm <file> [<file> ...]
rm -r <dir> [<dir> ...]
rm -rf <dir> [<dir> ...]
rm /secure <file> [<file> ...]
rm /recycle <file> [<file> ...]
rm --recycle <file> [<file> ...]
Deletes one or more files. Registered as both 'rm' and 'del' (they share a single handler), so either name works.
By default rm permanently deletes the named files. Use /recycle (or --recycle) to send them to the Recycle Bin (recoverable), or /secure (or --secure) to overwrite the file contents with zeros before deletion.
cshw accepts both Windows-style switches and common Unix aliases. The shell's switch-extraction step rejoins lexer-split "-X" / "--X" sequences before handlers see them, so for argument purposes /secure and --secure are interchangeable.
<file> File(s) to delete. The handler does not expand
wildcards itself; use the glob command for that:
rm `glob *.bak`
-r, -R, --recursive, /r
Remove directories and their contents recursively.
Without it, naming a directory is an error
("<name> is a directory").
-f, --force Do not report files that are not there. Commonly
combined as `rm -rf`.
/secure, --secure
Overwrite the file contents with zeros (size-
preserving in-place write, then close, then
DeleteFile). Useful when you want to make recovery
on local storage difficult. Mutually exclusive
with /recycle.
/recycle, --recycle
Send to the Recycle Bin instead of permanently
deleting. The operation FAILS rather than silently
falling back to permanent delete when the bin is
unavailable -- see NOTES on rmdir(1) for the full
list of refusal cases.
rm temp.txt
Permanently delete temp.txt.
rm /recycle bigfile.iso
Send bigfile.iso to the Recycle Bin (or fail if it can't fit).
rm --recycle bigfile.iso
Same, Unix-style spelling.
rm /secure passwords.txt
Overwrite passwords.txt with zeros, then delete it.
rm a.txt b.txt c.txt
Delete several files in one command.
0 All files deleted successfully. Other At least one delete failed. Per-file errors go to stderr.
Recursion: Earlier versions of this page stated that rm "does not recurse into directories -- use rmdir for that". That was simply wrong: -r, -R, --recursive and /r have all worked, and the page documented none of them.
Junctions and symbolic links: A recursive remove deletes the LINK, never what it points at. If a tree being removed contains a junction, the junction entry is unlinked and the target directory and its contents are left completely untouched.
This is worth stating plainly because it used to be false, and the consequence was data loss: rm descended THROUGH junctions and deleted the contents of the target, so removing a tree that merely contained a link destroyed files nowhere near the tree you named, silently, and still reported success.
Long paths: Recursive removal is not limited to MAX_PATH (260 characters); a tree nested deeper than that is removed normally.
/secure is best-effort: it writes zeros to the file's currently allocated clusters, but offers no guarantee against journaling, snapshots, SSD wear-leveling, or copies that already left the disk. For real sanitization, use a tool that addresses the storage layer directly.
rmdir back to top ↑remove directories
rmdir <dir>
rmdir /S [/Q] <dir>
rmdir -r [-q] <dir>
rmdir /recycle <dir>
rd ...
Aliases: rd
Removes (deletes) a directory. By default, only empty directories can be removed. Use /S (or -r / --recursive) to recursively delete a non-empty tree, or /recycle to send the directory (empty or not) to the Recycle Bin.
cshw accepts both Windows-style switches (/S, /Q, /recycle) and the common Unix aliases (-r, --recursive, -q, --quiet, --recycle). Behind the scenes, the shell's switch-extraction step rejoins lexer-split "-X" / "--X" sequences before handlers see them, so for argument purposes /S and -r are interchangeable.
<dir> The directory to remove.
/S, -r, --recursive
Recursively delete the directory and all of its
contents. Permanent -- no confirmation, no Recycle
Bin involvement. Use with care.
/Q, -q, --quiet
Suppress per-file error reporting during a recursive
delete. Has no effect without -r/-s.
/recycle, --recycle
Send the directory to the Recycle Bin instead of
permanently deleting it. Handles empty and non-empty
directories on its own; /S is unnecessary (and
silently a no-op when paired). The operation FAILS
rather than silently falling back to permanent delete
when the bin is unavailable -- see NOTES.
rmdir emptydir
Remove an empty directory.
rmdir /S /Q oldproject
Permanently delete a directory tree, suppressing per-file errors.
rmdir -r --quiet oldproject
Same as above using Unix-style switches.
rmdir /recycle scratch
Send the scratch directory (empty or not) to the Recycle Bin.
rd "Temporary Files"
Remove a directory whose name contains a space.
0 Success.
Other The command's $? value is the underlying Windows error code
from RemoveDirectoryW or, for /recycle, from IFileOperation.
Permanent deletion: /S deletes content immediately and irrevocably. There is no confirmation prompt. Double-check the path before pressing Enter.
Recycle Bin caveats: /recycle uses the Vista+ IFileOperation API with the FOFX_RECYCLEONDELETE flag set. That flag tells Windows to FAIL the operation rather than silently fall back to a permanent delete when the Recycle Bin can't accept the item: - the path is on a network/UNC share (which has no bin), - the item is larger than the bin's per-drive size budget, - the drive is removable and has no per-drive bin enabled, - or the bin is disabled by group policy on this drive. In all of those cases, the file/folder is left in place and the command returns failure. This matches the safety expectation of /recycle: "recoverable, or refuse."
In-use files: A recursive delete may fail partway through if any file in the tree is held open by another process. /Q suppresses per-file noise but does not change the behavior.
rundllproc back to top ↑call an exported function from a DLL
rundllproc [options] DLL FUNCTION [ARGS...]
rundllproc [options] ALIAS FUNCTION [ARGS...]
rundllproc [options] DLL #ORDINAL [ARGS...]
Loads a DLL (or reuses one previously preloaded with dllimport), resolves an exported function by name or ordinal, marshals up to 16 typed arguments and invokes it under SEH protection. The raw return value is available in %result; the printed Result line is formatted per --ret.
-v, --verbose Verbose output: handles, function address, arg shapes.
-r, --rundll32 Use the rundll32 entrypoint signature instead
(HWND, HINSTANCE, LPSTR cmdLine, int nCmdShow).
Args are joined into a single ANSI cmdLine.
--ret:TYPE Format the return value as TYPE:
int (default) decimal + hex
hex hex only
bool TRUE / FALSE
hresult HRESULT + FormatMessage text
wstr dereference as LPCWSTR
astr dereference as LPCSTR
ptr print as pointer 0x...
void suppress output
Each ARG is one token. Prefixes pin the type; unprefixed tokens are
auto-detected (number-shaped tokens become integers, anything else
becomes a wide-string pointer).
i:N Signed integer; decimal or 0xHEX. Sign-extended to a
pointer-sized slot.
u:N Unsigned / DWORD value (same width).
p:HEX Raw pointer-sized value (hex or decimal).
b:0|1 BOOL. Also accepts true / false / TRUE / FALSE.
s:STRING Wide string (LPCWSTR). The string lives until the call
returns.
a:STRING ANSI string (LPCSTR), converted from wide via CP_ACP.
null Explicit NULL pointer.
obufw:N Allocate an N-wide-char output buffer (zeroed). After
the call the contents up to the first NUL are printed
as a wide string.
obufa:N Allocate an N-byte output buffer (zeroed). Decoded as
ANSI text up to the first NUL.
obuf:N Allocate an N-byte output buffer (zeroed). Hex-dumped
after the call (16 bytes per row).
obufd:VALUE Allocate a 4-byte in/out DWORD initialized to VALUE.
After the call the slot is reprinted as DWORD.
obufq:VALUE Allocate an 8-byte in/out QWORD initialized to VALUE.
After the call the slot is reprinted as QWORD.
Up to 16 arguments are supported.
rundllproc kernel32.dll GetTickCount
Call a zero-arg function. Prints the tick count.
rundllproc kernel32.dll Sleep 250
Pass a single integer (auto-detected).
rundllproc user32.dll MessageBoxW 0 "Hello" "cshw" 0
Pass two integers and two wide strings (auto-detected).
rundllproc --ret:bool user32.dll IsWindow p:0x10010
Tell rundllproc to format the return as TRUE/FALSE; pass an
explicit pointer-sized value.
rundllproc --ret:hresult ole32.dll CoInitialize null
Print the return as an HRESULT with the FormatMessage text.
rundllproc --ret:wstr kernel32.dll GetCommandLineW
Treat the LPWSTR return value as a string and print it.
rundllproc --ret:bool kernel32.dll GetComputerNameW obufw:64 obufd:64
Real in/out call: a 64-wide-char buffer for the name and a
4-byte DWORD pre-initialized to 64 that the function updates
with the number of chars written.
rundllproc --ret:bool kernel32.dll GetEnvironmentVariableW s:PATH obufw:1024 i:1024
Read an environment variable into an output buffer; the third
arg is the buffer size in chars (a plain int, not in/out).
rundllproc -r shell32.dll Control_RunDLL desk.cpl
Use the rundll32-style entrypoint (HWND, HINSTANCE, LPSTR, int).
rundllproc mydll.dll #5
Look up function by ordinal.
dllimport user32.dll
rundllproc user32 GetForegroundWindow
Preload a DLL and refer to it by alias.
0 Function returned (its value is in %result; check it
yourself if the function uses a status code).
other DLL load failed, function not found, SEH exception
during the call, or a syntactic problem with arguments.
Safety: rundllproc invokes the function under __try / __except. Access violations and most hardware exceptions are caught and reported instead of crashing the shell -- but a corrupted process state (heap, stack walked too far, in-flight async work) can still leave the shell unhappy. Calling a function with the wrong arg shape is undefined behavior.
Calling convention: on x64 there is one calling convention so 0..16 DWORD_PTR slots cover almost any Win32 API. On x86 the helper typedefs are __cdecl; calling a __stdcall function with more args than its real arity can disturb the stack frame.
Sign extension: integer results are formatted as DWORD_PTR by default. A 32-bit signed return (e.g. lstrcmpW returning -1) will print as a large unsigned value because the upper 32 bits of the return register are zero on x64. Use --ret:hex if that is clearer, or compare against 0xFFFFFFFF.
say back to top ↑print a system value (time, date, hostname, etc.) and capture it
say <topic> [/fmt:<format>]
Prints a single system value to stdout and stores it in $result for script use. Supports time/date formatting via wcsftime-style format strings, plus a handful of identity, location, and system-probe topics.
Time / date topics (accept /fmt:<wcsftime-format>):
time Current time of day (default: HH:MM:SS.cs)
date Current date (default: MM/DD/YYYY)
datetime Date + time (default: YYYY-MM-DD HH:MM:SS)
now Alias for datetime
Identity / location:
hostname Computer name
user Current user name
cwd Current working directory
version cshw version string
os Friendly OS name + build (e.g. "Windows 11 (10.0.26100)")
System probes: additional topics like arch, build, etc. are
surfaced as the implementation grows; `say /?` (help) lists the
current set.
/fmt:<format>
wcsftime-style format string, e.g. /fmt:"%Y-%m-%d %H:%M".
Only meaningful for the time/date topics.
say hostname
set host = $result
say now /fmt:"%Y%m%d_%H%M%S"
set stamp = $result
echo "log_$stamp.txt"
say version
# prints "1.0.0.0" (or whatever the current version is)
0 Success; $result holds the value. 1 Unknown topic or bad format.
sed back to top ↑stream editor for filtering and transforming text
sed [OPTIONS]... SCRIPT [INPUT-FILE]...
sed [OPTIONS]... -e SCRIPT [-e SCRIPT]... [INPUT-FILE]...
sed [OPTIONS]... -f SCRIPT-FILE [INPUT-FILE]...
command | sed [OPTIONS]... SCRIPT
sed reads text from input files (or standard input), applies a script of editing commands to each line, and writes the result to standard output. It is the canonical Unix tool for non-interactive text editing -- search- and-replace, line filtering, conditional rewriting, and stream rewriting of any kind.
cshw's sed implements a substantial GNU sed subset, with PCRE2 as the regex engine (so lookahead, lookbehind, named groups, and Unicode classes all work) and dual Windows-style and Unix-style switch spellings. It also adds Windows-specific behaviors for line endings, BOMs, and the Recycle Bin.
-n, --quiet, --silent
Suppress automatic printing of pattern space at the end
of each cycle. Without this, sed prints every line that
wasn't deleted; with it, only lines explicitly printed
by p / P / s///p / = appear.
-e SCRIPT, --expression=SCRIPT
Add SCRIPT to the program. Multiple -e options accumulate.
-f FILE, --file=FILE
Add the contents of FILE to the program. Multiple -f
options accumulate. Mixes freely with -e.
-E, -r, --regexp-extended
Accepted for GNU sed compatibility. cshw's sed uses
PCRE2 syntax unconditionally, which is a superset of
ERE, so this flag is effectively a no-op.
-i[SUFFIX], --in-place[=SUFFIX]
Edit files in place. If SUFFIX is given, a backup with
that suffix is kept (e.g. -i.bak rewrites file.txt and
preserves file.txt.bak). Without a suffix, no backup is
kept. The original file's encoding and line-ending
style are preserved.
--recycle With -i, send the original file to the Recycle Bin
rather than overwriting it in place. The new content is
written to a fresh file at the original path. Provides
a soft-delete safety net even when no backup suffix is
given. Mutually exclusive with -c. Fails (rather than
silently falling back to a permanent overwrite) when
the Recycle Bin is unavailable; see NOTES.
-c, --copy With -i, write to a temporary file and then copy back
rather than rename. Slower but safe across hardlink
boundaries and OneDrive sync points.
-s, --separate
Treat input files as separate streams: line numbers,
$ (last line), and the t/T branch state reset for each
file. Without it, files are concatenated into a single
logical stream.
-u, --unbuffered
Flush output after each line.
-z, --null-data
Use the NUL byte (ASCII 0) as the record separator, on
OUTPUT as well as input. Useful with `find -print0`
style producers: `find . -print0 | sed -z ... `.
Output used to be terminated with a newline even under
-z, which defeats the point -- a -z record may legally
contain newlines. A record that does still picks up a
CR on each of them when written to stdout; see the
stdout note under "Line endings" below.
-l N, --line-length=N
Wrap the `l` command's output at column N. Default 70.
0 disables wrapping.
--posix Disable GNU extensions (a TEXT same-line form, T, R, W,
F, Q, z, 0~step, addr,+N, addr,~N, the e flag and
command, replacement-string case conversion). Useful
when porting strict POSIX scripts.
--sandbox Refuse to run any command that touches the host outside
the I/O streams: r, R, w, W, e, the e flag on s, and
the F command. The script either runs without those or
is rejected at parse time.
--crlf Force CRLF line endings on output, regardless of input.
--unix Force LF (Unix) line endings on output. Without --crlf
or --unix, sed auto-detects per file and writes back
what it read.
--debug Annotate output with the executing command and the
state of pattern / hold space at each cycle. Verbose;
useful for debugging non-trivial scripts.
--help Print the help screen and exit.
--version Print version and exit.
Switch aliases:
cshw accepts both Unix-style (-x / --xxx) and Windows-style (/x)
spellings everywhere. So `-i.bak`, `--in-place=.bak`, and
`/i:.bak` are all equivalent.
.SED SCRIPT LANGUAGE
A sed program consists of one or more commands, separated by newlines or
semicolons. Each command optionally begins with an ADDRESS that selects
which lines the command applies to. Comments begin with `#` and run to
end of line. The first line beginning with `#n` is equivalent to -n.
N Line number N (1-based). E.g. `5d` deletes line 5.
$ Last line of input.
/REGEX/ Lines matching REGEX.
\cREGEXc Same, with custom delimiter c (any non-newline char).
Useful when REGEX contains slashes:
\;/usr/local;d
// Empty regex re-uses the most recent regex from any
command in the script.
N,M Range: from line N through line M (inclusive).
N,$ From line N through end of input.
/RE1/,/RE2/ From the next line matching RE1 through the next line
matching RE2 thereafter (inclusive). Range "latches":
once entered, stays active until RE2 matches.
ADDR1,+N [GNU] N lines after ADDR1 (inclusive of ADDR1).
ADDR1,~N [GNU] Through the next line whose number is a multiple
of N.
FIRST~STEP [GNU] Every STEP lines starting at line FIRST.
E.g. `0~2` is even lines, `1~2` is odd lines.
0,/REGEX/ [GNU] Like /REGEX/,/REGEX/ but matches REGEX even on
line 1 (the standard form skips line 1 when looking
for the start of the range).
ADDR ! Negate: the command applies to lines NOT matching ADDR.
Substitution and transliteration:
s/RE/REPL/FLAGS
The workhorse. Substitute RE with REPL in pattern space.
Delimiter is whatever character follows `s` (commonly /
or | or #). Replacement specials:
& The whole match.
\& A literal &.
\1..\9 Capture group N.
\n,\t Newline, tab.
\r Carriage return.
\\ Literal backslash.
\l, \u Lowercase / uppercase the next character.
\L, \U Lowercase / uppercase until \E or end.
\E End \L / \U region.
\<nl> Embed a literal newline in the replacement.
Flags (any combination):
g Replace all occurrences (not just the first).
N Replace only the Nth occurrence (1-512).
Combine with g (`s/RE/REPL/3g`) to replace
from the Nth occurrence onward.
p Print pattern space if a substitution was made.
w FILE Append pattern space to FILE if substituted.
i, I Case-insensitive matching.
m, M Multi-line matching: ^ and $ match at
embedded newlines.
e Execute the result as a shell command.
Disabled when --sandbox is in effect.
(cshw also disables this by default for
safety; pass --enable-e to opt in.)
y/SRC/DST/ Transliterate: replace each occurrence of a character
in SRC with the corresponding character in DST. SRC and
DST must have the same length (after escape processing).
Pattern space output:
p Print the current pattern space.
P Print up to (and including) the first embedded newline
in pattern space.
= Print the current input line number.
l [N] Print pattern space "unambiguously": non-printable bytes
shown as \ooo octal, $ marks end of line, long lines
wrap at column N (default 70 or --line-length).
Pattern space lifecycle:
n Print pattern space (unless -n), then read the next
input line into pattern space. If no next line, exit.
N Append a newline and the next input line to pattern
space. If no next line, behavior depends on --posix:
strict POSIX exits without auto-printing; GNU prints
pattern space first.
d Delete pattern space, start next cycle (skip auto-print).
D Delete up to and including the first embedded newline
in pattern space; restart the cycle WITHOUT reading new
input (re-runs the script on whatever's left). If no
embedded newline, equivalent to d.
Hold space:
h Replace hold space with pattern space.
H Append \n + pattern space to hold space.
g Replace pattern space with hold space.
G Append \n + hold space to pattern space.
x Exchange the contents of pattern and hold space.
z [GNU] Zap (clear) pattern space.
Append / insert / change:
a TEXT Append TEXT after current line is output. TEXT can
a\ continue across lines using a backslash at end of line.
TEXT The single-line `a TEXT` form is a GNU extension; the
two-line `a\` + TEXT form is portable.
i TEXT Insert TEXT before current pattern space output.
i\ Same continuation rules as `a`.
c TEXT Replace pattern space with TEXT. With a range address,
c\ replaces the entire range with one copy of TEXT.
File I/O:
r FILE Queue contents of FILE to be output after the current
pattern space. If FILE doesn't exist, the command is
silently a no-op (matching GNU behavior).
R FILE [GNU] Queue ONE line from FILE per matching line.
Subsequent matches read subsequent lines until EOF.
w FILE Write current pattern space to FILE (append after the
first write per command per invocation; the file is
truncated on first write).
W FILE [GNU] Write up to the first embedded newline of pattern
space to FILE.
F [GNU] Print the name of the current input file.
Branching:
: LABEL Define a label.
b LABEL Unconditional branch to LABEL. Without a label, branch
to end of script (skip remaining commands this cycle).
t LABEL Branch if any successful s/// has occurred since the
last input line was read or the last branch.
T LABEL [GNU] Branch if NO successful s/// has occurred since
the last input line was read or the last branch.
Termination:
q [N] Print pattern space (unless -n), drain append queue,
exit with status N (default 0).
Q [N] [GNU] Quit without auto-printing or draining append
queue.
Grouping:
{ CMDS } Apply a block of commands as a single unit, useful with
addresses. Group can span multiple lines.
Misc:
#... Comment, runs to end of line. The first line of the
first script that begins exactly with `#n` enables -n.
nothing Empty commands (consecutive ; or empty -e args) are
tolerated.
sed 's/foo/bar/' file.txt
Replace first 'foo' on each line with 'bar'.
sed 's/foo/bar/g' file.txt
Replace ALL 'foo' with 'bar' on each line.
sed -n '5p' file.txt
Print only line 5.
sed '5d' file.txt
Print everything except line 5.
sed '/^#/d' config.ini
Strip comment lines.
sed -i.bak 's/old/new/g' notes.txt
In-place edit; keep notes.txt.bak as backup.
sed -i --recycle 's/old/new/g' notes.txt
In-place edit; send original to the Recycle Bin (recoverable).
sed -n '/BEGIN/,/END/p' file.txt
Print everything between BEGIN and END markers.
sed '5,$d' file.txt
Keep only the first 4 lines.
sed '0~3d' file.txt
Delete every 3rd line.
sed -e '/^$/d' -e 's/^[ \t]*//' file.txt
Strip blank lines, then strip leading whitespace.
sed 'y/abc/ABC/' file.txt
Uppercase a, b, c.
sed 's/.*/\U&/' file.txt
Uppercase every line. (\U..\E is a GNU replacement extension.)
sed -E 's/([a-z]+) ([a-z]+)/\2 \1/' names.txt
Swap two adjacent lowercase words. -E is accepted but no-op
(PCRE2 is the default flavor).
sed -n '
h
$!d
x
s/.*\n//
p
' file.txt
Print only the last line (manual implementation of tail -1).
type file.txt | sed 's/\r$//'
Strip trailing CR (one way to convert CRLF to LF on the fly).
Note: sed already auto-detects line endings; this is rarely
needed in cshw.
0 Successful completion. 1 At least one input file could not be opened. 2 Sed program syntax error, or a regex failed to compile. N The Q or q command exited with status N.
Regex flavor: cshw's sed uses PCRE2 (Perl Compatible Regular Expressions) for all pattern matching. This is a superset of ERE, so anything that works with `sed -E` on Linux works here. Strict GNU BRE (where (...) is literal and \(...\) is grouping) is NOT emulated -- always use ERE syntax. The -E / -r / --regexp-extended flags are accepted purely for command-line compatibility.
Line endings: Input is auto-detected per file: if the file uses CRLF on at least one line, the file is treated as CRLF and CRLFs are stripped before each line enters pattern space, then re-added on output. To force one or the other, use --crlf or --unix.
ROUND-TRIPPING IS AN -i GUARANTEE, NOT A STDOUT ONE. `sed -i` on an LF-only file leaves it LF-only. Writing to standard output goes through the shell's own redirection layer, which emits CRLF regardless -- `sed 's/x/y/' unix.txt > out.txt` produces a CRLF file. Use -i, or --unix with a tool that respects it, when the line endings matter.
Encodings: UTF-8, UTF-16-LE, UTF-16-BE are auto-detected via byte-order mark. Files with no BOM are read as UTF-8.
The BOM is preserved by -i. It is NOT preserved through standard output, for the same reason: the redirection layer, not sed, decides what a redirected stream looks like on disk.
In-place editing semantics: Without --recycle and without -c, sed renames a temp file over the original. This is fast and atomic on the same drive but breaks hardlinks and may confuse OneDrive/Dropbox; use -c if either matters.
With --recycle, sed:
1. Writes the new content to a temp file.
2. Sends the original file to the Recycle Bin (via Vista+
IFileOperation with FOFX_RECYCLEONDELETE, so it FAILS rather
than silently permanent-deleting if the bin is unavailable).
3. Renames the temp file into place.
If step 2 fails, the temp file is removed and the original is
untouched.
Recycle Bin caveats: --recycle refuses (instead of silently falling back to permanent delete) when: - the file is on a network/UNC share, - the file is larger than the per-drive Recycle Bin size budget, - the drive is removable and has no per-drive bin enabled, - or the bin is disabled by group policy on this drive. Same contract as `rm /recycle` and `rmdir /recycle`.
Sandbox mode: --sandbox rejects scripts that contain r, R, w, W, F, e, or the s///e flag at parse time, with a clear error pointing at the offending command. This is GNU-compatible behavior. Use --sandbox when running untrusted scripts, e.g. via stdin on a server.
Differences from GNU sed: * The `e` command and the s///e flag are disabled by default. Pass --enable-e to opt in. GNU sed allows them by default. * Strict BRE is not supported (PCRE2 / ERE only). * The --debug output format is similar but not byte-identical. * `l N` uses the cshw line-length when no command-local override is present; default is 70 to match GNU.
POSIX sed compatibility: --posix disables: same-line a / i / c text; `T`, `R`, `W`, `F`, `Q`, `z`; 0~step / addr,+N / addr,~N addresses; the s/// case- conversion replacement escapes (\l \u \L \U \E); the /g flag with a leading number; and embedded newlines in pattern space via N without auto-printing.
GNU sed manual: https://www.gnu.org/software/sed/manual/sed.html
POSIX sed: IEEE Std 1003.1-2017
semaphore back to top ↑counting semaphore
semaphore <name> create <initial> [max]
semaphore <name> acquire [/timeout:ms]
semaphore <name> tryacquire [/timeout:ms]
semaphore <name> release [count]
semaphore <name> status
semaphore <name> destroy
A named counting semaphore. create takes an initial count and an optional maximum (defaulting to initial, minimum 1). acquire decrements, blocking while the count is zero; release increments. Create before use -- acquiring an unknown name is an error. semcreate is a one-line shorthand for create.
create <initial> [max] Create with initial count (max defaults to initial).
acquire [/timeout:ms] Decrement, blocking; $? = 0 acquired, 1 timeout.
tryacquire [/timeout:ms]
Decrement if possible (or wait up to ms);
$? = 0 acquired, 1 would-block. Never fatal.
release [count] Increment by count (default 1).
status Show current count and max.
destroy Remove the semaphore.
ON FAILURE
`acquire` is FATAL: a failed acquire stops the script (or the coroutine),
because the line after it is the section the permit was guarding. Use
`tryacquire [/timeout:ms]` when not getting a permit is an outcome you mean to
handle -- it reports through $? and execution continues.
semcreate slots 3 # == semaphore slots create 3
semaphore slots acquire
# ... limited-concurrency work ...
semaphore slots release
0 Operation succeeded (acquire/tryacquire: got a slot). >0 Acquire timeout / would block, unknown name, or bad usage.
semcreate back to top ↑create a counting semaphore (shorthand)
semcreate <name> <initial> [max]
Shorthand for `semaphore <name> create <initial> [max]`. If max is omitted it defaults to initial -- a counting semaphore of fixed size. Use the semaphore command for acquire/release/status/destroy.
semcreate slots 4
semcreate lock 1 # a binary semaphore
0 Created. >0 Bad usage.
sendmessage back to top ↑send a Win32 message to a window (synchronous)
sendmessage <hwnd> <msg> [<wParam> [<lParam>]]
Calls SendMessageW(hwnd, msg, wParam, lParam) and blocks until the window's WndProc returns. The LRESULT is captured in $result as a long.
`msg` accepts symbolic WM_* names (case-insensitive) or hex/decimal numbers. Symbolic names are looked up in CSHW's built-in table; any message not in the table can still be addressed by number.
<hwnd> Target HWND in hex or decimal. Must satisfy IsWindow().
<msg> Symbolic name (WM_CLOSE, wm_command, WM_USER, ...) or
a number (0x10, 16, 273, ...).
<wParam> WPARAM. Default 0. Hex or decimal.
<lParam> LPARAM. Default 0. Hex or decimal.
Recognized symbolic names include: WM_NULL, WM_CREATE, WM_DESTROY,
WM_MOVE, WM_SIZE, WM_ACTIVATE, WM_SETFOCUS, WM_KILLFOCUS,
WM_ENABLE, WM_SETTEXT, WM_GETTEXT, WM_GETTEXTLENGTH, WM_PAINT,
WM_CLOSE, WM_QUIT, WM_SHOWWINDOW, WM_ACTIVATEAPP, WM_SETCURSOR,
WM_GETMINMAXINFO, WM_NOTIFY, WM_KEYDOWN, WM_KEYUP, WM_CHAR,
WM_SYSKEYDOWN, WM_SYSKEYUP, WM_COMMAND, WM_TIMER, WM_HSCROLL,
WM_VSCROLL, WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_LBUTTONUP,
WM_RBUTTONDOWN, WM_RBUTTONUP, WM_USER.
# Simulate a button click on control id 100 in window $w:
sendmessage $w WM_COMMAND 100 0
# Programmatically close a window:
sendmessage $w WM_CLOSE
# Set a window's text:
# (lParam is the address of the string in real Win32 -- not safe
# to pass a script string here; use SetWindowText via winapi for
# text-setting.)
0 Success. $result holds the LRESULT as a long. 1 Bad HWND, unparseable message, or bad wParam/lParam.
SendMessage is synchronous and may block on a misbehaving window. For fire-and-forget delivery use `postmessage`.
seq back to top ↑print sequence of numbers
seq LAST
seq FIRST LAST
seq FIRST INCREMENT LAST
Prints a sequence of numbers from FIRST to LAST, with optional INCREMENT. Useful for loops, generating test data, and numeric sequences.
LAST Print 1 to LAST.
FIRST LAST Print FIRST to LAST.
FIRST INCREMENT LAST
Print from FIRST to LAST by INCREMENT.
-s STRING Use STRING as separator (default: newline).
-w, --equal-width
Pad with leading zeros for equal width.
-f FORMAT Use printf-style FORMAT.
seq 5
Output: 1 2 3 4 5 (one per line)
seq 3 7
Output: 3 4 5 6 7
seq 0 2 10
Output: 0 2 4 6 8 10 (by 2)
seq 10 -1 1
Output: 10 9 8 7 6 5 4 3 2 1 (countdown)
seq -s ", " 5
Output: 1, 2, 3, 4, 5
seq -w 1 100
Output: 001 002 ... 099 100 (padded)
seq 0.5 0.5 3
Output: 0.5 1.0 1.5 2.0 2.5 3.0 (decimals)
# Loop example:
foreach i ($(seq 1 10))
echo "Iteration $i"
endforeach
0 Success 1 Invalid arguments
Floating Point: seq supports decimal numbers: seq 0.1 0.1 1.0
Negative Numbers: Both negative values and counting down work: seq -5 5 # -5 to 5 seq 5 -1 -5 # 5 down to -5
Use in Loops: seq is commonly used with foreach: foreach n ($(seq 1 100)) process_item $n endforeach
Generating Data: Useful for creating test files: seq 1000000 > numbers.txt
foreach, loop, echo
service back to top ↑manage Windows services
service list
service start NAME
service stop NAME
service restart NAME
service status NAME
service info NAME
Manages Windows services - background processes that run independently of user sessions. Can list, start, stop, restart, and query service status.
Subcommands:
list List all services with their status.
start NAME Start a stopped service.
stop NAME Stop a running service.
restart NAME Stop then start a service.
status NAME Show current status of a service.
info NAME Display detailed service information.
Options:
/all Include all services (not just running).
service list
List running services.
service list /all
List all services including stopped ones.
service status spooler
Check print spooler status.
service start wuauserv
Start Windows Update service.
service stop wuauserv
Stop Windows Update service.
service restart spooler
Restart print spooler (common fix for printing issues).
service info bits
Show detailed info about BITS service.
0 Success 1 Service not found 2 Access denied (need Administrator) 3 Service operation failed
Administrator Required: Starting and stopping services requires Administrator privileges. Run the shell as Administrator for service management.
Service Names: Use the short service name, not the display name. For example: - wuauserv (not "Windows Update") - spooler (not "Print Spooler") - bits (not "Background Intelligent Transfer Service")
Use 'service info' to see both names.
Common Services: wuauserv Windows Update spooler Print Spooler w32time Windows Time bits Background Intelligent Transfer Service dnscache DNS Client wsearch Windows Search
Startup Types: Services can be set to start automatically, manually, or be disabled. This command doesn't modify startup types.
processlist, kill, reg
set back to top ↑set or display shell variables
set
set NAME=VALUE
set NAME VALUE
Sets a shell variable or displays all currently defined shell variables. Without arguments, displays all shell variables and their values.
Shell variables are used for storing values that can be referenced later in commands and scripts using the $NAME syntax. Variables can hold strings, integers, or floating-point numbers, and CSHW automatically tracks the type.
Variables set with 'set' are shell-local and do not affect the system environment. Use 'setenv' to modify environment variables.
NAME The variable name. Must start with a letter or underscore,
followed by letters, digits, or underscores.
VALUE The value to assign. Can be:
- String: "hello world" or hello
- Integer: 42, -17, 0x1F (hex)
- Float: 3.14, -2.5, 1.0e-3
set
Display all shell variables.
set count=10
Set variable 'count' to integer 10.
set name="John Doe"
Set variable 'name' to a string with spaces.
set pi=3.14159
Set variable 'pi' to a floating-point number.
set path C:\Tools
Set variable 'path' (alternative syntax without =).
echo $count
Display the value of variable 'count'.
set result=$?
Store the last command's exit code in 'result'.
set files=$(dir /b *.txt)
Store command output in a variable (command substitution).
0 Success 1 Invalid variable name 2 Syntax error
Shell variables are separate from environment variables. Changes made with 'set' do not affect the process environment. Use 'setenv' for that purpose.
Variable Naming Rules: - Must start with a letter (a-z, A-Z) or underscore (_) - Can contain letters, digits (0-9), and underscores - Names are case-sensitive ($Name != $name)
Type Inference: CSHW automatically determines variable type based on the assigned value: - Integers: whole numbers (42, -17, 0xFF) - Floats: numbers with decimal points (3.14) or exponents (1e-3) - Strings: everything else ("hello", paths, etc.)
Use 'vartype' command to check a variable's inferred type.
Special Variables: $? Exit code of the last command $: Current working directory $$ Process ID of the shell
The variable model: csh has exactly ONE kind of variable -- a list of words. `set e = one` and `set e = ( one )` are the same thing, a list of one word, and `$e[1]` is that word in both. There is no separate "string" type to choose: a string IS a one-word list.
cshw keeps that and adds types on top -- Integer, Float, Array, Associative -- which is what makes `@` arithmetic, `vartype` and `hash` possible. The addition does not change the model: SUBSCRIPTING is by WORD on every variable, whatever its type.
set e = one $e[1] is "one", $#e is 1, $e[2] is empty set e = ( one ) identical in every respect set c = "two words" $c[1] is "two words" -- quoting makes one word
`$e[1]` used to return `o` for a scalar -- the first CHARACTER -- so the subscript meant one thing on an array and another on a string, decided by a type the script could not see.
To index CHARACTERS, use the substring form, which is separate syntax for a separate job and is 0-indexed (csh word indices are 1-indexed; both conventions are kept as they are rather than one being bent to match the other):
set s = "hello world"
${s:0:1} -> h one character
${s:0:5} -> hello a substring
${s:6} -> world to the end
$s[1] -> hello world
Arrays: Parentheses make an ARRAY, however many words are inside them:
set one = ( alpha ) $#one is 1, $one[1] is "alpha" set many = ( alpha beta ) $#many is 2 set none = ( ) $#none is 0 set flat = alpha a scalar, not a one-element array
That "however many" is the point. The array/scalar decision used to be made on the word count, so a group holding exactly one word became a string and `$one[1]` read `a` -- the first character. `$#one` said 1 either way, so the shape of a variable depended on how many files a glob matched: `set files = ( *.txt )` was an array with two matches and a string with one.
A signed number inside a group is one element: `set n = ( -42 )` holds "-42", while `set n = -42` is a scalar.
Shell settings (csh/tcsh compatibility): These are OPTIONS the shell reads, set with the bare `set NAME` form or given a value. Each one changes behaviour; none is decorative.
noclobber Refuse to truncate an existing file with `>`.
noglob Turn filename substitution off.
nonomatch A pattern matching nothing is passed through as
typed instead of being an error. Without it, csh's
default applies: the shell reports "PATTERN: No
match.", abandons the command line and sets the
status to 1, so `rm *.tmp` in a directory with no
.tmp files refuses rather than handing rm a literal
asterisk.
verbose Echo each command line as typed, before expansion.
echo Echo each command line after expansion. Together with
verbose this shows what a line turned into as well as
what it was. Both write to stderr, so a trace never
lands in a backtick capture. Distinct from the `echo
on`/`echo off` command, which gates the prompt.
printexitvalue Report "Exit N" on stderr after a command that exited
non-zero. A pipeline reports once, for the pipeline.
echo_style Which echo this is: bsd (the default), sysv, both or
none. See `man echo`.
cdpath A list of directories `cd` searches when a bare
relative name is not in the current directory.
histchars The character that introduces a history reference,
replacing `!`. csh takes two characters, the second
for `^old^new` quick substitution; only the first is
honoured, because quick substitution is not
implemented. History substitution runs at the
interactive prompt only, so this has no effect on a
script -- a `!` in a script file is always literal.
Shell values (published, not read): path PATH as a word list -- `foreach d ($path)` is the idiom dirstack The directory stack. $dirstack[1] is the CURRENT directory and deeper indices are the pushd stack, newest first, exactly as in tcsh. shell The running shell's own executable prompt The prompt string home The home directory cwd The current directory owd The directory before the last one that MOVED version cshw's version; osversion the Windows version
setenv back to top ↑set environment variable
setenv NAME VALUE
setenv NAME=VALUE
Sets or modifies an environment variable. Unlike shell variables (set), environment variables are inherited by child processes and can affect system behavior.
NAME Environment variable name.
VALUE Value to assign.
setenv PATH "C:\Tools;%PATH%"
Prepend C:\Tools to PATH.
setenv JAVA_HOME "C:\Program Files\Java\jdk-17"
Set JAVA_HOME for Java applications.
setenv DEBUG 1
Set a debug flag.
setenv MY_APP_CONFIG "C:\Config\app.ini"
Set application-specific variable.
0 Success 1 Invalid name 2 Error setting variable
Inheritance: Environment variables are inherited by child processes: - Programs started from the shell see these variables - Use for configuration that programs expect
Shell vs Environment Variables: - set: Shell-local, not inherited by children - setenv: Environment, inherited by children
Persistence: setenv changes only affect the current session and child processes. To permanently set environment variables, use System Properties or the Windows 'setx' command.
Common Variables: PATH Executable search path HOME User's home directory TEMP/TMP Temporary file directory USERNAME Current user name
Case Sensitivity: Environment variable names are case-insensitive on Windows (PATH = Path = path).
sha1sum back to top ↑compute SHA-1 message digest
sha1sum FILE...
command | sha1sum
Computes and displays the SHA-1 hash (160-bit) of files. SHA-1 produces a 40-character hexadecimal digest.
FILE One or more files to hash.
-c FILE Check SHA-1 sums against a checksum file.
sha1sum file.txt
Compute SHA-1 hash.
sha1sum *.zip
Hash multiple files.
sha1sum -c checksums.sha1
Verify files against checksums.
echo "test" | sha1sum
Hash a string.
0 Success (or all checksums verified) 1 Checksum mismatch 2 File not found
Piped input: With no file operand and a redirected stdin, sha1sum hashes what it is given and prints "-" in the filename column, the way GNU does. The stream is treated as text and hashed as UTF-8, so the digest matches what GNU produces for the same text. An interactive shell with nothing piped in gets the usage message rather than blocking on the terminal.
Security Warning: SHA-1 is cryptographically broken and should NOT be used for security purposes. Collisions have been demonstrated.
Acceptable uses for SHA-1: - Legacy system compatibility - Non-security checksums - Git commit IDs (uses SHA-1)
For security, use SHA-256 or SHA-512 instead.
Output Format: da39a3ee5e6b4b0d3255bfef95601890afd80709 filename
Git Compatibility: Git uses SHA-1 for commit and object IDs, so sha1sum can be useful when working with Git internals.
sha256sum back to top ↑compute SHA-256 message digest
sha256sum FILE...
command | sha256sum
Computes and displays the SHA-256 hash (256-bit) of files. SHA-256 is cryptographically secure and produces a 64-character hexadecimal digest.
SHA-256 is recommended for security applications including file integrity verification and digital signatures.
FILE One or more files to hash.
-c FILE Check SHA-256 sums against a checksum file.
sha256sum installer.exe
Compute SHA-256 hash.
sha256sum *.zip > checksums.sha256
Generate checksums for all ZIP files.
sha256sum -c checksums.sha256
Verify files against checksums.
echo "secret" | sha256sum
Hash a string (includes newline).
0 Success (or all checksums verified) 1 Checksum mismatch 2 File not found
Piped input: With no file operand and a redirected stdin, sha256sum hashes what it is given and prints "-" in the filename column, the way GNU does. The stream is treated as text and hashed as UTF-8, so the digest matches what GNU produces for the same text. An interactive shell with nothing piped in gets the usage message rather than blocking on the terminal.
Output Format: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 file.txt
Security: SHA-256 is part of the SHA-2 family and is considered cryptographically secure. It's suitable for: - File integrity verification - Digital signatures - Password hashing (with proper salting) - Blockchain and cryptocurrency
Verification: Software downloads often provide SHA-256 checksums. Always verify: sha256sum -c downloaded.sha256
Speed: SHA-256 is slower than MD5 but provides much stronger security.
sha512sum back to top ↑compute SHA-512 message digest
sha512sum FILE...
command | sha512sum
Computes and displays the SHA-512 hash (512-bit) of files. SHA-512 produces a 128-character hexadecimal digest. Part of the SHA-2 family, it offers the highest security level.
FILE One or more files to hash.
-c FILE Check SHA-512 sums against a checksum file.
sha512sum file.txt
Compute SHA-512 hash.
sha512sum important.doc > important.sha512
Save checksum to file.
sha512sum -c checksums.sha512
Verify files against checksums.
sha512sum *.iso
Hash multiple ISO files.
0 Success (or all checksums verified) 1 Checksum mismatch 2 File not found
Piped input: With no file operand and a redirected stdin, sha512sum hashes what it is given and prints "-" in the filename column, the way GNU does. The stream is treated as text and hashed as UTF-8, so the digest matches what GNU produces for the same text. An interactive shell with nothing piped in gets the usage message rather than blocking on the terminal.
Security: SHA-512 is the strongest SHA-2 variant. Suitable for: - High-security file integrity - Cryptographic applications - Password hashing (with salt)
Output Format: cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e file
Performance: SHA-512 is actually faster than SHA-256 on 64-bit systems due to using 64-bit operations natively.
When to Use: - Maximum security requirements - Long-term archives - Cryptographic protocols - When 256 bits isn't enough
shadow back to top ↑hide a built-in so a program of the same name runs instead
shadow
shadow COMMAND ...
Takes a built-in out of command lookup without destroying it, so a program of the same name on PATH answers instead.
With no arguments, lists the commands currently shadowed.
cshw ships built-ins that share a name with real Windows programs -- `tree` and `vol` are both `%SystemRoot%\System32` executables as well, and Git ships its own `dir.exe`. The built-in wins, which is the point: a command means the same thing on every machine regardless of what else is installed. `shadow` is how you say "not this time" for one name, without giving up that guarantee for everything else.
shadow tree tree now runs C:\Windows\System32\tree.com unshadow tree tree the built-in again
Nothing is deleted. The command is set aside and `unshadow` puts it back, so a shadow is always reversible -- see NOTES.
COMMAND A built-in to hide. Several may be named at once.
Shadowing something already shadowed is not an error.
shadow
List what is currently hidden.
shadow dir
Hand `dir` to whatever is on PATH -- Git's dir.exe, say, if you
want GNU coreutils behaviour for one session.
shadow tree vol
Two at once.
unshadow -a
Undo all of it.
0 Every named command was hidden, or already was. 1 At least one name could not be.
When nothing replaces it: `shadow` hides a command, it does not swap one in. If no program on PATH answers to the name, the name simply stops resolving:
shadow vol vol -> ERROR: 'vol' is not recognized ...
That is the intended answer rather than an oversight. Hiding a built-in with nothing behind it SHOULD leave the name unresolvable; quietly falling back to the thing you just hid would make the command meaningless.
What cannot be shadowed: Only built-ins. An alias is not one -- use `unalias` for those, which shadow will tell you. And `shadow` refuses to shadow itself or `unshadow`, because those are the way back.
Reversibility: The built-in is moved into the same store `rcl` uses when a plugin claims an intrinsic's name, and is restored from it. Nothing in cshw can permanently remove a built-in; a shell one bad line away from being unusable is not a shell anyone should have to trust.
Scope: A shadow lasts for the session. Put the line in a startup script to make it persistent -- and if a startup script has shadowed more than you remember, `shadow` with no arguments says what, and `unshadow -a` clears the lot.
Finding out what will run: `which` reports the RESOLUTION, not the built-in, and says why:
which tree tree: cshw built-in command shadow tree ; which tree C:\Windows\System32\tree.com (shadowed intrinsic)
A shadowed name is never described as a built-in, because it is no longer what runs.
share back to top ↑assign a variable in the global namespace (write-through)
share <name> = <value>
share <name>[<index>] = <value>
share <name>{<key>} = <value>
Like `set`, but always writes through to the global variable namespace even when called from inside a proc or a coroutine.
Inside a proc, plain `set foo = 1` creates a procedure-local variable that disappears on return. Inside a coroutine, plain `set` creates a coroutine-local variable invisible to the main script thread.
`share` bypasses both. The variable is created/updated in the global namespace, visible to every thread and outliving any proc / coroutine scope.
<name> Variable name. Same naming rules as `set`.
<value> The value to assign. Supports the same forms `set`
supports: integer literals, floats, quoted strings,
command-substitution, etc.
# Coroutine writes a result back to the main thread:
share _ready = 0
proc worker
sleep 2
share _ready = 1
endproc
spawn worker
while ($_ready == 0)
sleep 0.1
end
echo "worker finished"
# Procedure publishes a return value via a shared var instead of
# the conventional $result -- useful when multiple values matter:
proc compute
share answer = 42
share message = "ok"
endproc
compute
echo "$answer / $message"
0 Variable was written. 1 Syntax error or readonly violation.
`share` is the canonical way for a coroutine to communicate results back to the main script thread. Coroutine-local `set` writes are isolated by design; `share` is the explicit opt-in to break that isolation.
WM_CLOSE veto handlers (see `bindevent`) similarly use `share` to report user intent back to the script that's waiting on the dialog.
shasum back to top ↑compute or verify a SHA hash with a selectable algorithm
shasum FILE...
shasum -a BITS FILE...
shasum BITS FILE...
shasum [-a BITS] -c CHECKSUM-FILE...
command | shasum [-a BITS]
Computes SHA digests, or verifies files against a saved list of them. Without -a the algorithm is SHA-256.
Output is the standard checksum-file format -- the hex digest, two spaces, the filename -- so `shasum *.exe > sums.txt` followed later by `shasum -c sums.txt` is the whole workflow. The format is shared with md5sum, sha1sum, sha256sum and sha512sum, which are the same tool with the algorithm fixed.
`shasum BITS FILE...` -- the bit size as a bare leading operand -- is cshw's own older spelling and still works. It is read as an algorithm only when it names one AND a file follows it, so `shasum 256` on its own hashes a file named 256.
FILE File(s) to hash.
-a BITS Algorithm to use:
1 SHA-1 (160-bit) - NOT SECURE
256 SHA-256 (256-bit) - DEFAULT
384 SHA-384 (384-bit)
512 SHA-512 (512-bit)
-c, --check Treat each operand as a checksum file and verify the
files it lists. Prints "name: OK" or "name: FAILED"
per entry. Combine with -a if the file was written
with something other than SHA-256.
shasum file.txt
Compute the SHA-256 digest.
shasum -a 512 file.txt
Compute the SHA-512 digest.
shasum -a 1 legacy.dll
SHA-1, for checking against an old published digest.
shasum *.exe > checksums.txt
Record digests for every executable here.
shasum -c checksums.txt
Verify them again later.
shasum -c checksums.txt > /dev/null || echo "something changed"
A mismatch sets the status without ending the script.
shasum 256 file.exe
The older cshw spelling; same as -a 256.
0 Every digest computed, or every checked file matched.
1 A checked file did not match, a file could not be read, or
the bit size was not one shasum supports.
No SHA-224: Earlier versions of this page listed 224. CryptoAPI, which supplies the digests, has no SHA-224 provider, so `-a 224` is refused rather than silently answered with a different algorithm.
A mismatch is a result, not a failure: -c reports each file and sets the exit status to 1 if any did not match. It does not add a command-failure line on top of that, so `shasum -c sums.txt || handle_it` reads cleanly.
Piped input: With no file operand and a redirected stdin, shasum hashes what it is given and prints "-" in the filename column, the way GNU does. The stream is treated as text and hashed as UTF-8, so `echo secret | shasum` yields the same digest GNU produces for the same line. An interactive shell with nothing piped in still gets the usage message rather than blocking on the terminal.
Algorithm selection: - SHA-1: legacy only, broken cryptographically - SHA-256: recommended for most uses, and the default - SHA-384: truncated SHA-512 - SHA-512: widest digest available here
shift back to top ↑shift positional parameters
shift
shift N
Shifts positional parameters ($1, $2, etc.) to the left. After shift, $2 becomes $1, $3 becomes $2, and so on. The old $1 is discarded.
N Number of positions to shift (default: 1).
# Script: process_args.csh
# Called with: process_args a b c d
echo $1 # a
shift
echo $1 # b (was $2)
shift
echo $1 # c (was $3)
# Shift by 2:
shift 2
echo $1 # d (was $4)
# Process all arguments:
while ($# > 0)
echo "Processing: $1"
shift
endwhile
0 Success 1 No arguments to shift
Use in Scripts: shift is commonly used in scripts to process command-line arguments one at a time, especially when argument count varies.
$# Variable: $# contains the argument count. After shift, $# decreases by 1.
Processing Options: Common pattern for handling options: while ($# > 0) if ($1 == "-v") set verbose=1 else if ($1 == "-o") shift set output=$1 else # Regular argument process $1 endif shift endwhile
Empty Arguments: Shifting when no arguments remain produces an error.
shutdown back to top ↑shutdown, restart, or log off the system
shutdown [options]
shutdown /s
shutdown /r
shutdown /l
Shuts down, restarts, or logs off the computer. Can also abort a pending shutdown operation. Requires appropriate privileges for shutdown/restart.
/s Shutdown the computer.
/r Restart the computer.
/l Log off the current user.
/h Hibernate (if supported).
/a Abort a pending shutdown.
/t SECONDS Time delay before action (default: 30).
/f Force running applications to close.
/c "MESSAGE" Display a comment/reason (max 512 chars).
/p Immediate poweroff (no timeout, no warning).
shutdown /s
Shutdown in 30 seconds.
shutdown /r /t 0
Immediate restart.
shutdown /l
Log off current user.
shutdown /s /t 60 /c "Maintenance in 1 minute"
Shutdown in 60 seconds with message.
shutdown /a
Cancel pending shutdown.
shutdown /r /f
Restart, force-closing applications.
shutdown /h
Hibernate the system.
shutdown /p
Immediate power off (no delay).
0 Success (operation initiated) 1 Access denied 2 Invalid argument
Force Close: Without /f, shutdown waits for applications to close gracefully. With /f, applications are forcefully terminated (may lose unsaved work).
Abort Window: During the timeout period, use 'shutdown /a' to cancel.
Privileges: Shutdown and restart require appropriate privileges. On domain computers, group policy may restrict these operations.
Remote Shutdown: Windows supports remote shutdown with /m \\computer option, though this may require additional configuration.
Scheduled Tasks: For scheduled shutdowns, consider using Task Scheduler instead of leaving a shutdown command pending.
sleep back to top ↑pause the current thread of execution for a duration
sleep DURATION
Blocks the current thread of execution for DURATION. In the interactive shell that means the prompt pauses; inside a coroutine it pauses just that coroutine while the rest of the shell keeps running.
DURATION is a number with an optional unit suffix. Fractional values are accepted and rounded to the nearest millisecond. The maximum duration is about 49 days (the 32-bit millisecond cap that Win32 Sleep() uses).
DURATION Number + optional unit. Recognised suffixes:
ms milliseconds
s (default) seconds
m minutes
h hours
d days
Long-form aliases (millisecond, sec, secs, min, mins,
hour, hours, day, days) are also accepted.
sleep 5
Pause for 5 seconds (default unit is seconds).
sleep 0.5
Pause for 500 milliseconds.
sleep 100ms
Pause for 100 milliseconds.
sleep 2s
Pause for 2 seconds.
sleep 5m
Pause for 5 minutes.
sleep 1.5h
Pause for one hour and thirty minutes.
sleep 1d
Pause for 24 hours.
# In a polling loop:
while (1)
processlist | grep myprogram
sleep 5s
endwhile
# Inside a coroutine -- only this coroutine pauses:
corunproc myproc {
sleep 1m
echo "minute elapsed"
}
0 Success.
1 Missing argument, negative value, unknown unit, or
duration over the 49-day cap.
sleep blocks the calling thread (Win32 Sleep). For per-coroutine pauses, just call sleep inside the coroutine -- it will not block the shell.
To pause until a system event rather than a time, write the polling loop yourself with a 'while' and a short sleep, or use 'corunproc' to do the waiting on a worker.
To prevent the *system* from sleeping while a long task runs, see 'suspend keepawake'.
socket back to top ↑low-level socket operations
socket <subcommand> [args...]
Provides low-level TCP and UDP socket operations for network programming. Sockets are identified by names (user-assigned or auto-generated like "sock1").
create [-4|-6] [--dual] [--keep-mapped] tcp|udp [name]
Create a new socket. Returns socket id in $result.
Type can be 'tcp' (SOCK_STREAM) or 'udp' (SOCK_DGRAM).
Default family is IPv4. Pass -6 (or --ipv6) for an IPv6 socket.
--dual
For IPv6 sockets, clear IPV6_V6ONLY before bind so the same
socket accepts both IPv6 and IPv4 clients. Implies -6; using
it with -4 is an error.
--keep-mapped
By default, when a v4 client connects to a dual-stack v6
listener, its address is stripped from ::ffff:a.b.c.d to plain
a.b.c.d in 'socket info' and 'socket accept' output, and the
accepted socket's family is reported as IPv4. Pass this flag
to keep the on-the-wire v6 form. Only meaningful with --dual.
bind <sock> [addr] <port>
Bind socket to address and port. Address defaults to the wildcard for
the socket's family: 0.0.0.0 for IPv4, :: for IPv6. Quote IPv6 literals
on the command line: socket bind v6sock "::1" 8080
listen <sock> [backlog]
Start listening for connections. Backlog defaults to SOMAXCONN.
accept <sock> [/timeout:ms] [name]
Accept an incoming connection. Returns new socket id in $result.
Use /timeout to specify maximum wait time in milliseconds.
connect <sock> <host> <port> [/timeout:ms]
Connect to a remote server. Host can be IP address or hostname.
send <sock> <data>
Send data through the socket. Data is sent as UTF-8.
recv <sock> [maxbytes] [/timeout:ms]
Receive data from socket. Result stored in $result.
Default maxbytes is 4096. Timeout returns empty string (not error).
close <sock> | /all
Close a socket or all open sockets.
list
Display all open sockets with their state and addresses.
info <sock>
Show detailed information about a socket.
select <sock> r|w|e [/timeout:ms]
Check if socket is readable (r), writable (w), or has errors (e).
Multiple modes can be combined (e.g., "rw"). Result contains matched modes.
/timeout:ms, /t:ms
Specify timeout in milliseconds for blocking operations.
# Simple TCP server
socket create tcp server
socket bind server 8080
socket listen server
set client (socket accept server)
socket recv $client
echo "Received: $result"
socket send $client "Hello back!"
socket close $client
socket close server
# Simple TCP client
socket create tcp
socket connect $result localhost 8080
socket send $result "Hello server"
socket recv $result
echo "Response: $result"
socket close $result
# UDP example
socket create udp sender
socket connect sender 192.168.1.100 5000
socket send sender "UDP message"
socket close sender
# Check socket readability with timeout
socket select mysock r /timeout:5000
if $result == "r"
socket recv mysock
endif
0 Success >0 Error (check $errorlevel for WSA error code)
10048 WSAEADDRINUSE - Address already in use
10060 WSAETIMEDOUT - Connection timed out
10061 WSAECONNREFUSED - Connection refused
sort back to top ↑sort lines of text
sort [options] FILE
command | sort [options]
Sorts lines of text alphabetically or numerically. By default, sorts in ascending order using the entire line as the sort key.
FILE File to sort.
-r, --reverse Sort in descending order.
-n, --numeric Sort numerically instead of alphabetically.
-u, --unique Remove duplicate lines (output unique lines only).
-f, --ignore-case
Ignore case when sorting.
-t CHAR Use CHAR as field delimiter.
-k N Sort by field N (1-based).
sort names.txt
Sort file alphabetically.
sort -r names.txt
Sort in reverse order.
sort -n numbers.txt
Sort numerically (1, 2, 10 not 1, 10, 2).
sort -u data.txt
Sort and remove duplicates.
dir /b | sort
Sort directory listing.
sort -t, -k2 data.csv
Sort CSV by second column.
sort -f words.txt
Case-insensitive sort.
type log.txt | grep ERROR | sort -u
Get unique sorted error lines.
0 Success 1 File not found 2 Error
Stability: The sort is stable - equal elements maintain their relative order.
Numeric vs Alphabetic: Without -n, "10" sorts before "2" (alphabetically). With -n, "2" sorts before "10" (numerically).
Memory: Large files are sorted in memory. Very large files may require significant RAM.
Locale: Sort order may be affected by system locale settings.
source back to top ↑execute commands from a file in the current shell
source FILE
. FILE
Reads and executes commands from FILE in the current shell environment. Unlike running a script normally, source executes in the current shell, so variable changes and alias definitions persist after the file executes.
This is the standard way to load configuration files and define procedures.
FILE Script file to execute.
source config.csh
Load configuration file.
source ~/.cshrc
Load shell startup file.
source functions.csh
Load procedure definitions.
. mysetup.csh
Short form using dot notation.
source env_setup.csh && echo "Environment loaded"
Load and confirm.
Returns the exit status of the last command executed in the file.
Variable Scope: Variables set in the sourced file become available in the current shell. This is different from running a script as a subprocess.
Use Cases: - Loading configuration: source ~/.cshrc - Setting up environment: source project_env.csh - Defining procedures: source myfunctions.csh
Startup Scripts: On interactive startup, CSHW loads a startup file if present. It first looks for %USERPROFILE%\.cshrc. If that file is missing, it falls back to %APPDATA%\cshw\cshwrc.
Error Handling: If an error occurs during sourcing, subsequent commands in the file may still execute. Use 'exit' in the script if fatal errors should stop execution.
Dot Command: The '.' command is an alias for 'source' (UNIX tradition): . config.csh
spawn back to top ↑start another cshw instance in a new console window
spawn
spawn [options] -c COMMAND
spawn [options] -k COMMAND
spawn [options] SCRIPT [ARGS...]
Launches a second cshw in its own console window. The new shell re-invokes the same binary that is running now -- a development build spawns itself, not whatever `cshw` happens to resolve to on PATH.
The new shell inherits the current working directory and the exported environment. Shell-local variables, aliases, completions and job state do NOT cross; the new shell reads .cshrc and settings.csh for itself, exactly as if it had been launched from Explorer.
With no arguments, spawn opens a plain interactive window. With -c the new shell runs COMMAND and closes; with -k it runs COMMAND and then stays at an interactive prompt, which is what makes `spawn -k "cd C:\proj"` useful.
spawn is deliberately not called "fork". Windows has no fork: there is no address-space copy and no shared descriptor table between the two shells. What you get is a fresh process, which is what CreateProcess provides.
-c COMMAND Run COMMAND in the new shell, then exit.
-k COMMAND Run COMMAND in the new shell, then stay interactive.
SCRIPT [ARGS] Run a script file in the new shell.
/d PATH Start in PATH instead of the current directory.
Also accepted as /d:PATH.
/title TEXT Set the new window's title.
/min Start the window minimized.
/max Start the window maximized.
/wait Wait for the new shell to exit and adopt its exit
code as $status.
/here Reuse this console instead of opening a window. The
nested shell shares this shell's standard handles and
any redirection in effect. Implies /wait.
Options must appear BEFORE -c or -k. Like cmd's /C and /K, everything after
-c or -k is taken as the command, so a switch written after it becomes part
of the command text rather than an option to spawn.
spawn
Open a new interactive cshw window in the current directory.
spawn -k "cd C:\proj"
New window already parked in C:\proj.
spawn -c "ls -l"
Run a command in a new window, then close it.
spawn /title "build log" -k "tail -f build.log"
Named window following a log file.
spawn /min /wait build.cshw release
Run a script minimized, block until it finishes, adopt its status.
spawn /here
Nested shell in the current console; `exit` returns to the parent.
spawn /here -c "exit 4" || echo "child failed"
/here implies /wait, so $status carries the child's 4 and the
|| chainer fires.
0 New shell started (or, with /wait, exited 0) N With /wait or /here, the child shell's own exit code 1 Could not start the new shell 2 Unknown option
Exit status: Without /wait, spawn returns as soon as the child is created and prints the new process id, so a script can kill it later. It does not wait, and the child's eventual exit code is not observable. With /wait or /here, the child's exit code is published to $status verbatim -- not flattened to 1 -- so chainers and `if` tests see the real value.
Redirection: A new console window has its own standard handles, so redirecting spawn's output does not capture the child's. Use /here when you want the child to write into this shell's stdout, or have the child redirect internally: spawn -c "ls -l > listing.txt"
Environment inheritance: setenv writes through to the process environment block, so exported variables reach the child. `set` variables are shell-local and do not. Pass those explicitly: spawn -k "set target = $target"
splash back to top ↑show a modeless splash dialog during a long-running step
splash [<mode> [<duration_ms>]]
Puts up a modeless splash dialog and returns immediately, so the script keeps running with the splash on top. Typical use: cover a long step (downloads, init, build) so the user sees something other than a console.
Dismiss with `endsplash`, or wait for the timer when mode=timed.
Calling `splash` while one is already showing is a no-op.
The modeless splash ignores mouse clicks and the OK / close buttons -- only `endsplash` (or the timer, for mode=timed) dismisses it.
<mode> One of:
splash (default) title + tagline
timed same look; auto-dismisses
after <duration_ms>
about | verbose | logo | none
<duration_ms> Only meaningful for mode=timed. Default 3000 ms.
The script does NOT wait for the timer to fire.
splash
Show the default splash. Dismiss with endsplash later.
splash logo
Show the logo variant.
splash timed 5000
Show for 5 seconds and auto-dismiss. Script continues immediately.
splash
# ... do long-running work ...
endsplash
0 Success (or splash already showing -- treated as success). 1 UI thread not available (non-interactive mode without it).
The modal counterpart is `testsplash` -- internal/dev-only and not part of the public surface.
splitpath back to top ↑print the components of a path, one per line
splitpath <path>
Split <path> into its individual directory/name components and print each on its own line. Both forward slashes and backslashes are recognized as separators.
Empty components -- from a leading separator or doubled separators -- and a leading drive specifier such as "C:" are skipped, so what comes back is just the list of names.
This pairs naturally with foreach: the output drops straight into a word list.
foreach part (`splitpath C:\dir\subdir\file.txt`)
echo $part
end
splitpath is a pure text operation; it does not touch the filesystem.
splitpath C:\dir\subdir\subdir2
Prints three lines: dir, then subdir, then subdir2
splitpath /usr/lib/file
Prints three lines: usr, then lib, then file
Zero on success. splitpath with no path argument is a usage error.
start back to top ↑start a program or open a file
start [OPTIONS] PROGRAM [ARGS...]
start [OPTIONS] FILE
start [OPTIONS] URL
Starts a program in a new window, opens a document with its associated application, or opens a URL in the default browser. Unless /wait is given, the shell does not wait for the program to complete.
PROGRAM Program to execute.
FILE File to open with associated application.
URL Web address to open in browser.
ARGS Arguments to pass to the program.
/min Start window minimized.
/max Start window maximized.
/wait Wait for the program to terminate and adopt its exit
code as $status.
/b Run on this console instead of creating a new window.
The child shares this shell's stdio, so its output can
be piped or captured.
/d PATH Set starting directory. Also accepted as /d:PATH.
/i Pass the environment cshw was launched with, ignoring
any setenv changes made since.
Options must appear BEFORE the target; the first non-switch argument is
taken as the program, file or URL, and everything after it is passed
through as arguments.
/b and /i take the direct process-launch path rather than the Windows
shell association layer, so they apply to executables only -- not to
documents or URLs.
start notepad
Open Notepad in new window.
start notepad document.txt
Open document in Notepad.
start document.docx
Open Word document (with associated app).
start https://www.google.com
Open URL in default browser.
start /max excel report.xlsx
Open Excel maximized with file.
start /wait setup.exe
Run installer and wait for completion.
start /d "C:\Projects" cmd
Open command prompt in specific directory.
start /min background.exe
Start program minimized.
start /b /wait cmd /c "echo hi"
Run on this console and capture its output; without /wait the
shell returns before the child writes anything.
start /wait setup.exe || echo "installer failed"
/wait publishes the real exit code, so chainers branch on it.
0 Success (program started) N With /wait, the program's own exit code 1 Program/file not found 2 Error starting program or unknown option
New Window: start creates a new window/process. The shell continues immediately unless /wait is specified.
File Associations: For documents, Windows opens the associated application: - .docx -> Microsoft Word - .pdf -> PDF reader - .html -> Web browser
Path Spaces: If the path contains spaces and you use a title, put the title first: start "My Title" "C:\Program Files\App.exe"
Without Title: Use empty quotes for title if path has spaces: start "" "C:\Path With Spaces\program.exe"
Background Programs: Use start for launching programs that should run independently of the shell session.
stat back to top ↑display file status information
stat [-c FORMAT | --format=FORMAT | --printf=FORMAT] FILE...
Displays detailed information about files including size, timestamps, attributes, and owner. Provides more detail than dir for individual files.
With -c, prints only what FORMAT asks for, which is what makes stat usable from a script:
set bytes = `stat -c %s report.txt`
-c FORMAT Print FORMAT for each file instead of the full listing,
--format=FORMAT followed by a newline.
--printf=FORMAT The same, WITHOUT the trailing newline.
FILE One or more files to examine.
%n file name, as given %N file name in quotes
%s size in bytes %F regular file / directory /
%h number of hard links symbolic link
%i file index (inode) %d volume serial (device)
%U owner account name %G group account name
%A permissions, as ls -l %a permissions, octal
%y modification time %Y ...as seconds since the epoch
%x access time %X ...as seconds since the epoch
%w creation (birth) time %W ...as seconds since the epoch
%% a literal %
\n, \t, \r and \\ are the escapes you would expect.
An unrecognised specifier is an error, not a passthrough -- a format
that quietly printed %Q because nobody implemented it would be the
sort of silent success this shell tries not to have.
%A and %a are a Windows APPROXIMATION of a Unix concept, computed the
same way `ls -l` computes its mode column: read-only clears `w`, and
an executable extension (.exe, .com, .bat, .cmd, .ps1, .cshw) sets
`x`. They agree with `ls -l` by construction. Windows has no mode
bits, so no better answer exists -- see `man chmod`.
stat document.txt
Display full status of document.txt.
stat -c %s report.txt
Just the size, for a script to capture.
stat -c "%n is %s bytes, a %F, mode %A (%a)" report.txt
report.txt is 6 bytes, a regular file, mode -rw-r--r-- (644)
stat --printf="%Y\n" build.log
Modification time as an epoch second, for comparing two files.
stat *.exe
Show status of all executables.
stat "C:\Program Files"
Examine a directory.
0 Success 1 File not found 2 Access denied
Information Displayed: - Full path - File size in bytes - Creation time - Last modification time - Last access time - File attributes (read-only, hidden, system, archive) - Owner (if accessible)
Attributes: R = Read-only H = Hidden S = System A = Archive D = Directory L = Reparse point (symlink/junction)
Timestamps: Windows maintains three timestamps per file. Access time updates may be disabled on some systems for performance.
stop back to top ↑suspend a running job
stop %JOBID
stop PID
Suspends (pauses) a running job or process. The job remains in memory but stops executing until resumed with 'bg' or 'fg'.
Stopping a job that is ALREADY stopped succeeds and does nothing, so a script can reach a known state without checking first. It used to report "failed to suspend job N" at status 1, which reads as though the job were still running and the shell could not touch it.
Stopping a job that has already finished is an error, and says so rather than blaming a suspend that could never have worked.
%JOBID Job number from 'jobs' command (prefixed with %).
PID Process ID to suspend.
stop %1
Suspend job number 1.
stop %2
Suspend job number 2.
jobs
# [1] Running longprocess.exe
# [2] Running another.exe
stop %1
jobs
# [1] Stopped longprocess.exe
# [2] Running another.exe
0 Success 1 No such job 2 Cannot stop job
Difference from Kill: - stop: Pauses the process (can be resumed) - kill: Terminates the process (cannot be resumed)
Resuming: Use 'fg %JOBID' to resume in foreground. Use 'bg %JOBID' to resume in background.
Interactive Stop: Pressing Ctrl+Z in the terminal also stops the foreground process.
System Processes: Some system processes cannot be stopped without Administrator privileges.
strings back to top ↑extract printable strings from files
strings [options] FILE
strings FILE
Extracts and displays sequences of printable characters from files, particularly useful for examining binary files. Finds text embedded in executables, DLLs, and other binary formats.
FILE File to examine.
-n LENGTH Minimum string length (default: 4).
-a Scan entire file (default).
-t FORMAT Print offset (d=decimal, o=octal, x=hex).
strings program.exe
Find strings in an executable.
strings -n 10 binary.dat
Find strings at least 10 characters long.
strings -t x malware.exe
Show strings with hex offsets.
strings file.dll | grep -i password
Search for password-related strings.
strings *.exe | grep -i "http://"
Find URLs in executables.
strings image.jpg
Find metadata text in images.
0 Success 1 File not found 2 Read error
Default Behavior: By default, strings extracts ASCII sequences of 4+ characters. This catches most meaningful text while filtering noise.
Security Analysis: strings is valuable for malware analysis and reverse engineering. It can reveal: - Hardcoded URLs, IPs, filenames - Error messages and debug strings - Function names and API calls - Embedded credentials (don't do this!)
Binary Analysis: Combined with grep, strings is a quick way to search binary files for specific patterns: strings malware.bin | grep -E 'http|ftp|password'
sudo back to top ↑run command as Administrator
sudo COMMAND [ARGS...]
Runs a command with elevated (Administrator) privileges. On Windows, this triggers User Account Control (UAC) to request elevation. The command runs in a new elevated process.
COMMAND The command to run elevated.
ARGS Arguments to pass to the command.
sudo notepad C:\Windows\System32\drivers\etc\hosts
Edit hosts file (requires admin).
sudo reg add HKLM\SOFTWARE\Test /v Key /d Value
Modify HKLM registry (requires admin).
sudo service start wuauserv
Start Windows Update service.
sudo netsh firewall show config
View firewall configuration.
sudo cmd /c "net user Administrator /active:yes"
Enable Administrator account.
Returns the exit code of the elevated command, or: 1 UAC cancelled by user 2 Error launching elevated process
UAC Prompt: Windows displays a User Account Control prompt asking for permission. If denied, the command does not run.
New Window: The elevated command typically runs in a new console window, as Windows doesn't allow mixing elevation levels in one console.
When Needed: Administrator rights are required for: - Modifying system files - HKEY_LOCAL_MACHINE registry changes - Service management - Network configuration - Installing software system-wide
Already Elevated: If the shell is already running as Administrator, sudo simply runs the command normally.
Security: Be cautious with sudo. Only elevate commands you trust and understand.
suspend back to top ↑manage system power state from the shell
suspend
suspend status
suspend keepawake [on | off]
suspend keepawake while DURATION
suspend manages the system's power state. It does NOT pause shell execution -- use 'sleep' for that.
The only state currently managed is "keepawake", which prevents the system from going to sleep or hibernating while cshw is running. The underlying mechanism is SetThreadExecutionState with the ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED flags, refreshed by a background thread every fifteen seconds.
When cshw exits, the keepawake state is automatically released and normal Windows power management resumes -- so even if you forget to turn it off, the system goes back to its configured timeouts as soon as you close the shell.
status Print 'keepawake: on' or 'keepawake: off'.
(Running 'suspend' alone is the same.)
keepawake With no further argument: print current
state. Same as 'status'.
keepawake on Start preventing system sleep / hibernation.
keepawake off Stop preventing system sleep / hibernation.
keepawake while DUR Turn keepawake on, sleep DUR (same syntax
as the sleep command), then restore the
previous keepawake state. Useful for "stay
awake for the next two hours then revert".
suspend keepawake on
Don't let the box sleep while cshw runs.
suspend keepawake off
Restore default power management.
suspend keepawake while 2h
Stay awake for two hours, then go back to whatever the
keepawake state was before.
suspend status
Query: prints 'keepawake: on' or 'keepawake: off'.
0 Success.
1 Syntax error (unknown subcommand, unknown argument,
missing DURATION, or bad DURATION).
This is a runtime hint to the OS, not a registry change. It does the same thing as the powercfg block:
powercfg /change standby-timeout-ac 0 powercfg /change standby-timeout-dc 0 powercfg /change monitor-timeout-ac 0 ...
except (a) it auto-restores when cshw exits, (b) it doesn't persist across reboots, and (c) it doesn't require admin. It will not override group policy on locked-down machines.
The 'suspend' command used to also pause the shell for a duration (e.g. 'suspend 5 minutes'). That role has moved to 'sleep', which now accepts unit suffixes ('sleep 5m'). 'suspend' with a bare number prints a redirect message.
sync back to top ↑list and destroy synchronization objects
sync list [type]
sync destroy <type> <name>
sync destroyall
Manages the process-wide table of named synchronization objects created by mutex, event, semaphore, barrier, and channel. list shows them (optionally filtered to one type); destroy removes a single object; destroyall clears the whole table. type is one of: mutex, event, semaphore, barrier, channel.
list [type] List all objects, or just those of type.
destroy <type> <name> Destroy one named object.
destroyall Destroy every synchronization object.
sync list
sync list channel
sync destroy mutex m
sync destroyall
0 Always (destroy of a missing name reports "not found"). >0 Bad usage / unknown type.
tac back to top ↑concatenate and print files in reverse line order
tac [file...]
tac [/reverse | --reverse]
Reverse-order concatenation, the cat-spelled-backwards companion to `cat`. With multiple files the FILE ORDER is kept and each file's lines are reversed within it, which is what GNU tac does: `tac a b` prints a's lines reversed, then b's lines reversed.
Internally, `tac` is `cat` with reverseDefault=true; it shares all the cat infrastructure, so options that work for `cat` (line numbering, BOM-aware encoding detection, etc.) work for `tac`.
/reverse, --reverse
Cancel the default reversal -- effectively makes tac behave
like cat for that one invocation. Mainly useful in scripts
that conditionally choose tac or cat.
file...
Files to read. Reads stdin when none are given.
See `man cat` for the full set of formatting flags (-n, -b, -s,
-E, -T, -v, -A, -e, -t, -q, -u) -- all available for tac too.
tac log.txt
Print log.txt with the lines reversed.
cat log.txt | tac
Same effect via pipe.
tac access.log error.log
access.log's lines reversed, then error.log's. The files stay in
the order given; only the lines inside each are reversed.
0 Success. 1 File not found or I/O error.
tail back to top ↑output the last part of files
tail [options] FILE
tail -n COUNT FILE
command | tail [options]
Outputs the last part of files or piped input. By default, prints the last 10 lines. Essential for viewing log files and monitoring output.
FILE File to read from.
-n COUNT Output the last COUNT lines (default: 10).
-COUNT Shorthand for -n COUNT (e.g., -20).
-n +COUNT Output starting from line COUNT (skip first COUNT-1 lines).
-c COUNT Output the last COUNT bytes instead of lines.
-f, --follow Keep file open and output new lines as they're appended.
Useful for monitoring log files. Press Ctrl+C to stop.
tail file.txt
Display last 10 lines of file.txt.
tail -n 20 log.txt
Display last 20 lines.
tail -50 error.log
Display last 50 lines (shorthand).
tail -f access.log
Monitor log file in real-time (follow mode).
tail -n +5 data.txt
Output everything starting from line 5.
processlist | tail -n 5
Show last 5 processes in list.
tail -c 256 binary.dat
Show last 256 bytes.
0 Success 1 File not found 2 Read error
Follow Mode: The -f flag is particularly useful for monitoring log files. The shell keeps the file open and displays new content as it's written. Use Ctrl+C to exit follow mode.
Log Monitoring: Common pattern for monitoring logs: tail -f /var/log/app.log | grep -i error
Line Selection: Use -n +N to skip the first N-1 lines and output the rest. This is useful for skipping headers: tail -n +2 data.csv # Skip header row
tar back to top ↑archive files
tar -c [-z] [-v] -f ARCHIVE [-C DIR] FILES...
tar -x [-z] [-v] -f ARCHIVE [-C DIR]
tar -t [-v] -f ARCHIVE
Creates, extracts, or lists the contents of tar archives. Supports both plain tar and gzip-compressed (.tar.gz or .tgz) archives.
tar (tape archive) is the standard UNIX archive format. CSHW's tar implementation provides core functionality for bundling files together.
Operation mode (one required):
-c, --create Create a new archive.
-x, --extract Extract files from archive.
-t, --list List archive contents.
Modifiers:
-f ARCHIVE Specify archive filename (required).
-z, --gzip Use gzip compression/decompression.
-v, --verbose Verbose output (list files processed).
-C DIR With -x, extract into DIR.
With -c, read the FILES from DIR and store them under
the names given -- `tar -cf a.tar -C build out`
archives `out`, not `build/out`, which is what makes
the archive unpack where it was meant to.
tar -cvf backup.tar Documents/
Create archive of Documents folder.
tar -czvf backup.tar.gz Documents/
Create gzip-compressed archive.
tar -tvf backup.tar
List contents of archive.
tar -xvf backup.tar
Extract archive in current directory.
tar -xvf backup.tar -C /restore
Extract to specific directory.
tar -xzvf backup.tar.gz
Extract gzip-compressed archive.
tar -cvf project.tar *.cpp *.h Makefile
Archive specific files.
0 Success 1 Archive error (corrupt, not found) 2 I/O error 3 Invalid arguments
Archive Format: CSHW's tar uses standard POSIX ustar format, compatible with other tar implementations.
Gzip Compression: The -z flag enables gzip compression. Files are typically named .tar.gz or .tgz when compressed.
Permissions: Windows doesn't have UNIX permissions. CSHW stores basic attributes but permission bits may not be meaningful on Windows.
Long Filenames: The ustar format supports filenames up to 255 characters. Longer names may be truncated.
Symbolic Links: Windows symbolic links (created with mklink) are archived as their target paths.
Large Files: Files up to 8GB are supported. Larger files require extended formats not currently implemented.
tc back to top ↑time how long a command takes to run
tc [/v] command [argument ...]
Run a command and report how long it took. Everything after tc -- and an optional leading /v switch -- is taken from the raw command line and run fresh in the current shell, so the command keeps its own switches, quoting, pipes, and redirection.
tc records a high-resolution timestamp before the command starts and again after it finishes, then prints the elapsed wall-clock time in seconds.
With /v (verbose), tc also prints the command line that ran and its exit status.
tc is transparent: after it returns, $status and $? hold the exit status of the command that ran, not tc's own -- so tc can be dropped in front of any command without disturbing status checks or && / || chains.
The elapsed time is also stored, in seconds, in the shell variable $timecount, so a script can read the measurement and act on it.
tc sort big.txt
Sorts the file, then prints e.g. "tc: 1.204 s".
tc /v grep -r needle .
Runs the recursive grep, then prints the command line, the
elapsed time, and the exit status.
tc sleep 2
Prints roughly "tc: 2.001 s".
The exit status is that of the timed command -- tc is transparent. Running tc with no command is a usage error.
The elapsed time is wall-clock time, so it includes any time the command spent waiting on I/O, other processes, or the system.
tcpclient back to top ↑one-shot TCP client
tcpclient <host> <port> [options]
One-shot TCP client that connects to a server, optionally sends data, optionally receives a response, and closes the connection.
This is a convenience command for simple request/response patterns. For more complex interactions or persistent connections, use the low-level socket command instead.
-4 | --ipv4
Force IPv4. Errors out if the host can't be reached over IPv4.
-6 | --ipv6
Force IPv6. Errors out if the host can't be reached over IPv6.
Quote IPv6 literals: tcpclient "::1" 8080
/send:"data"
Send the specified data after connecting.
Quotes are optional but recommended for data with spaces.
/recv
Receive response data. Result is stored in $result.
/timeout:ms
Connection and receive timeout in milliseconds.
Default is 5000 (5 seconds).
When neither -4 nor -6 is given, the family is auto-detected. A literal IP address picks its own family. A hostname is resolved with the OS resolver under AF_UNSPEC; whichever family it returns first wins (this honors the system's preference rules, e.g. RFC 6724 / Windows source-address policy).
# Check if a server is listening (connect test)
tcpclient localhost 8080
if $? == 0
echo "Server is up"
else
echo "Server is down"
endif
# Send data and receive response
tcpclient localhost 8080 /send:"hello" /recv
echo "Response: $result"
# HTTP GET request
tcpclient example.com 80 /send:"GET / HTTP/1.0\r\nHost: example.com\r\n\r\n" /recv
echo $result
# With custom timeout
tcpclient slow-server.com 8080 /timeout:30000 /recv
# Check website availability
tcpclient google.com 443
if $? == 0
echo "Google is reachable"
endif
localhost is IPv6 first: On a current Windows box `localhost` resolves to ::1 before 127.0.0.1, while tcpserver binds IPv4 unless told otherwise. So pairing a plain `tcpserver 8080 handler` with `tcpclient localhost 8080` connects to nothing and waits for the timeout. Either name the v4 address -- `tcpclient 127.0.0.1 8080` -- or start the server dual-stack with `tcpserver --dual 8080 handler`, which binds both families.
Escape Sequences: Use \r\n for carriage return + line feed (HTTP requires this). Example: "GET / HTTP/1.0\r\n\r\n"
HTTPS: This command does not support SSL/TLS. For HTTPS, use the fetch command instead.
Response Handling: The command waits for the connection to close or timeout before returning all received data. For streaming responses, use the low-level socket commands.
0 Success >0 Connection failed, timeout, or error
tcpserver back to top ↑start a TCP server
tcpserver <port> <handler_proc> [options]
Starts a TCP server that listens on the specified port and calls a handler procedure for each incoming connection.
The server creates a socket, binds to the port, and enters an accept loop. For each accepted connection, it calls the handler procedure with the client socket ID as an argument.
By default, the server runs indefinitely. Use /max or /timeout to limit.
-4 | --ipv4
Bind the IPv4 wildcard 0.0.0.0 (default).
-6 | --ipv6
Bind the IPv6 wildcard ::. By default this listens IPv6-only;
accepted clients must reach the server over IPv6.
--dual
Bind ::, but clear IPV6_V6ONLY so the same socket accepts both
IPv6 and IPv4 clients. Implies -6; conflicts with -4.
--keep-mapped
With --dual, v4 peers normally appear as plain a.b.c.d in
'socket info' and the accepted socket's family is reported as
IPv4. Pass --keep-mapped to leave the on-the-wire ::ffff:a.b.c.d
form intact and report the family as IPv6 instead.
/max:N
Accept at most N connections, then exit.
/timeout:ms
Stop after timeout milliseconds with no new connections.
/once
Same as /max:1 - accept one connection and exit.
/mthread
Handle connections CONCURRENTLY. The default server processes one
connection at a time (the handler runs inline in the accept loop);
with /mthread the server is backed by the cshw::net::CServer engine,
which accepts on a dedicated thread and runs each handler on its own
worker thread, so slow handlers no longer block new connections.
Each handler gets an isolated variable scope (as with coroutines).
Combine with /max to bound the run, /timeout to stop after an idle
period, or run it inside a coroutine for background use and cancellation
(see CANCELLATION below). -4/-6/--dual/--keep-mapped all apply.
A /mthread server normally blocks until /max is reached. To run one in the
background and stop it on demand, wrap it in a procedure, start it with
corunproc, and stop it with cocancel:
proc server_proc()
tcpserver 8080 my_handler /mthread
endproc
corunproc server_proc # returns a coroutine id
...
cocancel <coid> # or: cocancel /all
cocancel shuts the listener down cleanly. Handlers written as a loop are
cancelled GRACEFULLY: cshw loops poll the cancellation flag, so the loop breaks
on its own and the handler can run its own cleanup (e.g. 'socket close'):
proc my_handler(sock)
while 1
socket recv $sock /timeout:500
# ... handle $result ...
end
socket close $sock # runs cleanly on cancel
endproc
A handler parked in a plain blocking 'socket recv' (no /timeout, no loop) can't
notice cancellation, so the server force-closes its socket to wake it; that
recv then returns an error. Prefer the loop + /timeout shape above for clean
cancellation.
The handler procedure receives the client socket ID as its first argument.
The procedure is responsible for:
- Reading from the socket (socket recv)
- Writing to the socket (socket send)
- Closing the socket when done (socket close)
Example handler:
proc echo_handler(sock)
socket recv $sock
socket send $sock $result
socket close $sock
endproc
# Echo server - returns whatever client sends
proc echo_handler(sock)
socket recv $sock
socket send $sock $result
socket close $sock
endproc
tcpserver 8080 echo_handler
# HTTP server example
proc http_handler(sock)
socket recv $sock
socket send $sock "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!"
socket close $sock
endproc
tcpserver 80 http_handler
# Accept only 10 connections
tcpserver 8080 handler /max:10
# Accept one connection (useful for testing)
tcpserver 8080 handler /once
# Run server in background using coroutine
corunproc tcpserver 8080 handler
echo "Server started in background"
Running in Background: To run the server in the background, use corunproc: corunproc tcpserver 8080 myHandler The server will run in a separate coroutine while you continue working in the shell.
Port Reuse: The server sets SO_REUSEADDR to allow quick restarts without waiting for TIME_WAIT to expire.
0 Success (server exited normally) >0 Error (bind failed, listen failed, etc.)
tee back to top ↑read from stdin and write to stdout and files
command | tee FILE
command | tee FILE1 FILE2...
command | tee [options] FILE
Reads from standard input and writes to both standard output AND one or more files. Like a "T" pipe fitting that splits the data flow.
FILE File(s) to write to.
-a, --append Append to files instead of overwriting.
-i, --ignore-interrupts
Ignore interrupt signals.
dir | tee listing.txt
Display dir output AND save to file.
build.bat | tee build.log
Show build output while logging.
command | tee file1.txt file2.txt
Write to multiple files.
command | tee -a log.txt
Append to existing log.
longprocess | tee output.log | grep ERROR
Log everything, display only errors.
tar -cvf - src/ | tee backup.tar | md5sum
Create archive and compute checksum simultaneously.
0 Success 1 Write error
Non-Destructive Piping: Without tee, you choose either viewing OR saving: command > file # Saved but not displayed command # Displayed but not saved command | tee file # Both!
Multiple Outputs: tee can write to multiple files simultaneously: command | tee log1.txt log2.txt log3.txt
Pipeline Position: tee is typically in the middle of a pipeline: producer | tee file | consumer
Append Mode: Use -a to add to existing files rather than overwriting: status_check | tee -a daily.log
Real-Time Output: Output appears in real-time, not after completion.
test back to top ↑evaluate a conditional expression
test <expression>
[ <expression> ]
Evaluate <expression> and report the result as the exit status: 0 when the expression is true, 1 when it is false, and 2 when the expression is malformed. test produces no output on success -- it exists to drive the && / || operators and $status checks.
`[` is an alias for test that requires a closing `]` as its final argument, so these two lines are equivalent:
test -f config.txt [ -f config.txt ]
String tests: -z STR true if STR is empty -n STR true if STR is non-empty STR true if STR is non-empty (one-argument form) STR1 = STR2 true if the strings are equal (== is also accepted) STR1 != STR2 true if the strings differ
Integer tests (operands are compared numerically): N1 -eq N2 equal N1 -ne N2 not equal N1 -lt N2 less than N1 -le N2 less or equal N1 -gt N2 greater than N1 -ge N2 greater or equal
File tests: -e PATH PATH exists -f PATH PATH exists and is a regular file -d PATH PATH exists and is a directory -s PATH PATH exists and is not empty -r PATH PATH is readable -w PATH PATH is writable -x PATH PATH is executable
Negation: ! EXPR true if EXPR is false
To combine conditions, use the shell's own && and || between separate test invocations rather than -a / -o.
test -f settings.cshw && source settings.cshw
[ -n "$name" ] && echo "hello, $name"
test $count -gt 10
if ($status != 0) echo "too many"
0 if the expression is true, 1 if false, 2 if it is malformed.
testsplash back to top ↑[INTERNAL] exercise the splash dialog in a chosen mode
testsplash [<mode> [<duration_ms>]]
INTERNAL / DEV-ONLY command. Not part of the public cshw command surface. Exists so developers can exercise every mode of the modal splash dialog during development.
For scripted use, see the public `splash` command (modeless, script-friendly lifecycle).
Same mode set as `splash`. See `man splash` for the list.
The name is deliberately awkward to discourage scripting use. If you reach for this in a real script, you almost certainly want `splash` + `endsplash` instead.
time back to top ↑measure command execution time
time COMMAND [ARGS...]
Executes a command and reports the time taken to complete. Shows real (wall-clock) time, user CPU time, and system CPU time.
COMMAND Command to execute and time.
ARGS Arguments for the command.
time dir /s
Time a recursive directory listing.
time find . -name "*.cpp"
Time a file search.
time sort largefile.txt > sorted.txt
Time a sort operation.
time build.bat
Time a build script.
Returns the exit code of the timed command.
Output Format: real 0m1.234s # Wall-clock time user 0m0.567s # CPU time in user mode sys 0m0.123s # CPU time in kernel mode
Real vs CPU Time: - Real: Actual elapsed time (includes I/O waits) - User: CPU time executing your code - Sys: CPU time in system calls
Performance Analysis: - High real, low CPU: I/O bound (waiting for disk/network) - High CPU, matches real: CPU bound (computation)
Multicore: User+sys can exceed real if multiple cores are used.
Precision: Timing precision depends on Windows timer resolution, typically around 15.6ms on desktop Windows.
Scripts: Useful for identifying slow operations in scripts or comparing different approaches.
timeout back to top ↑run command with time limit
timeout DURATION COMMAND [ARGS...]
timeout [options] DURATION COMMAND
Runs a command and kills it if it doesn't complete within the specified time limit. Useful for commands that might hang or take too long.
DURATION Time limit (seconds, or with suffix: s/m/h).
COMMAND Command to run.
ARGS Arguments for the command.
-s SIGNAL Signal to send on timeout (default: KILL).
-k DURATION Kill with SIGKILL after DURATION if still running.
--preserve-status
Exit with command's status even on timeout.
timeout 30 ping server.com
Run ping for max 30 seconds.
timeout 5m build.bat
Allow 5 minutes for build.
timeout 1h longprocess.exe
1 hour limit.
timeout 10 curl https://slow-server.com/file
Kill download if it takes over 10 seconds.
timeout 60 script.bat || echo "Timed out!"
Handle timeout case.
124 Command timed out 125 timeout command failed 126 Command found but not executable 127 Command not found Other Command's exit status (if completed)
Time Units: 30 30 seconds 30s 30 seconds 5m 5 minutes 1h 1 hour
Graceful Termination: By default, timeout sends a termination request. Use -k to ensure the process is killed if it ignores the request.
Use Cases: - Network commands that might hang - Build processes with time limits - Automated testing with deadlines - CI/CD pipeline steps
Scripting: Check exit code 124 to detect timeouts: timeout 10 command if ($? == 124) echo "Command timed out" endif
title back to top ↑set or display the console window title
title [text ...]
Sets the console window title to the given text. With no arguments, prints the current title to stdout and stores it in $result.
When multiple positional arguments are supplied, they are joined with spaces before being applied.
title
Print the current title.
title "Build server"
Set the title to "Build server".
title cshw -- backup running
Sets title to "cshw -- backup running" (positional join).
0 Always.
tokenize back to top ↑display parsed tokens from input
tokenize LINE
tokenize "COMMAND WITH ARGS"
Parses a command line and displays the tokens identified by the lexer. Useful for debugging command parsing, understanding how the shell interprets input, and developing shell scripts.
LINE Text to tokenize.
tokenize "echo hello world"
# Token 0: Identifier "echo"
# Token 1: Identifier "hello"
# Token 2: Identifier "world"
tokenize "set x=42"
# Token 0: Identifier "set"
# Token 1: Identifier "x"
# Token 2: Operator "="
# Token 3: Number "42"
tokenize 'grep -i "pattern" file.txt'
# Shows how quotes and switches are parsed
tokenize "dir /s /b *.txt"
# Token 0: Identifier "dir"
# Token 1: Switch "/s"
# Token 2: Switch "/b"
# Token 3: Identifier "*.txt"
0 Success
Token Types: - Identifier: Commands, filenames, arguments - String: Quoted text - Number: Numeric values - Operator: =, |, <, >, etc. - Switch: /x or -x style options - Variable: $name references
Debugging: tokenize helps understand: - How quotes are handled - Where words are split - How special characters are interpreted
Parser Development: Essential tool when developing or debugging shell scripts that depend on specific parsing behavior.
touch back to top ↑change file timestamps or create empty files
touch FILE...
touch [options] FILE...
Updates the access and modification times of files to the current time. If a file doesn't exist, touch creates an empty file with that name.
touch is commonly used to create empty files or to update timestamps for build systems that depend on file modification times.
FILE File(s) to touch.
-a Change only the access time.
-m Change only the modification time.
With neither, both are set, as GNU touch does.
-c, --no-create Do not create files that do not exist.
-t TIMESTAMP Use this time instead of the current time.
Format: [[CC]YY]MMDDhhmm[.ss]
A two-digit year 69-99 means 1969-1999; 00-68 means
2000-2068. With no year at all, the current year.
-d, --date=STR Use this time instead of the current time.
Format: "YYYY-MM-DD [HH:MM[:SS]]". This is not GNU's
full free-form date parser -- a string it cannot read
is refused, never silently treated as "now".
-r, --reference=FILE
Use FILE's modification time.
touch newfile.txt
Create empty file or update existing file's timestamp.
touch file1.txt file2.txt file3.txt
Touch multiple files.
touch -c maybeexists.txt
Update timestamp only if file exists.
touch -m important.dat
Update only modification time.
touch *.cpp
Update timestamps on all C++ source files.
touch -t 202601151200 dated.txt
Set the timestamp to 15 January 2026, 12:00 local time.
touch -d "2026-01-15 12:00" dated.txt
The same, spelled readably.
touch -r template.txt copy.txt
Give copy.txt the same modification time as template.txt.
0 Success 1 Cannot create file (permission denied) 2 Invalid arguments
Creating Files: touch is the standard way to create empty files in a shell. It's cleaner than "echo. > file" or similar.
Build Systems: touch is useful for forcing rebuilds in make-based systems by updating source file timestamps.
Timestamps: Windows files have creation, modification and access times. touch sets the modification and access times; the creation time is left alone.
Daylight saving: A timestamp given to -t or -d is local wall-clock time, converted with the DST rule in force ON THAT DATE rather than the one in force today. Setting a January time during the summer therefore stores January's offset, and reading it back with `stat` or `dir` returns the time that was asked for. Both directions used the current bias before, so half the year every timestamp from the other half was an hour out.
Time options used to be inert: -t was accepted and ignored, so `touch -t 202601151200 f` stamped f with the current time and returned 0 -- a script building a file with a known mtime silently got today instead.
tr back to top ↑translate or delete characters
tr SET1 SET2
tr -d SET1
command | tr SET1 SET2
Translates, squeezes, or deletes characters from standard input, writing to standard output. Useful for character substitution and cleanup.
SET1 Source character set.
SET2 Replacement character set.
-d, --delete Delete characters in SET1 (no replacement).
-s, --squeeze Replace repeated characters with single occurrence.
-c, --complement
Use complement of SET1.
Character classes:
[:alnum:] Letters and digits
[:alpha:] Letters
[:digit:] Digits
[:lower:] Lowercase letters
[:upper:] Uppercase letters
[:space:] Whitespace
[:punct:] Punctuation
echo "hello" | tr a-z A-Z
Convert to uppercase: HELLO
echo "HELLO" | tr A-Z a-z
Convert to lowercase: hello
echo "hello world" | tr -s ' '
Squeeze spaces: "hello world"
echo "abc123" | tr -d '0-9'
Delete digits: abc
echo "hello" | tr 'aeiou' '12345'
Replace vowels: h2ll4
type file.txt | tr '\r\n' '\n'
Convert Windows to Unix line endings.
echo "a,b,c" | tr ',' '\n'
Replace commas with newlines.
echo "hello world" | tr -d ' '
Remove all spaces: helloworld
type file.txt | tr -d '\r'
Remove carriage returns.
echo "hello" | tr -c 'aeiou' '_'
Replace non-vowels: _e__o
0 Success 1 Error
Character Ranges: - a-z: Lowercase letters - A-Z: Uppercase letters - 0-9: Digits
Special Characters: - \n: Newline - \r: Carriage return - \t: Tab - \\: Backslash
One-to-One Mapping: Characters in SET1 map to corresponding positions in SET2. If SET2 is shorter, its last character is repeated.
Common Uses: - Case conversion - Removing unwanted characters - Line ending conversion - Character substitution
tree back to top ↑display a directory structure graphically
tree [PATH] [/f] [/a]
Draws the directory structure below PATH, one line per entry, with the branch characters that show which levels are still open. With no PATH, draws the current directory.
Directories are listed alphabetically and case-insensitively, which is the order Windows itself presents them in.
/f Include files as well as directories. Files are listed
before subdirectories at each level, as cmd's tree does.
/a Draw with ASCII (+--- \--- |) instead of the line-drawing
characters. Use it when the output is heading somewhere
that cannot render them -- a log file read on another
machine, or a terminal in a single-byte code page.
tree
The current directory, directories only.
tree /f
...including files.
tree C:\Projects\site /f /a
A named directory, files included, in plain ASCII.
tree > structure.txt
Capture it. Consider /a as well, since a file has no font.
0 The tree was drawn 1 PATH does not exist or is not a directory
A reparse point -- a junction or a symbolic link to a directory -- is listed but NOT descended. A junction pointing at one of its own ancestors would otherwise turn the listing into a walk with no end, and one pointing across the disk would silently include a tree that is not below PATH at all.
Paths are opened in extended-length form, so a tree deeper than MAX_PATH is drawn completely rather than stopping partway down without saying so.
true back to top ↑succeed or fail with no side effects
true
false
nop
Three minimal commands that perform no work and only affect $status:
true Sets $status to 0 (success). false Sets $status to 1 (failure). nop Identical to true. A no-op placeholder; succeeds.
`nop` is dispatcher-aliased to `true` and shares the same handler. Comment lines starting with `#` are discarded by the lexer before dispatch, so they neither run nor touch $status.
Useful in shell constructs that require a command but where you want a guaranteed success/failure, as a placeholder in empty branches, or to deliberately seed $status before a conditional.
true
Succeed. $status = 0.
false
Fail. $status = 1.
nop
Same as true. Useful as a placeholder.
if ($condition)
nop # explicit no-op in the empty branch
else
# ...
endif
proc always_fail
false
endproc
true, nop 0 Always. false 1 Always.
true vs nop: Functionally identical -- both succeed without side effects. true is the conventional Unix name; nop is the legacy cshw spelling. Both remain registered and point at the same handler.
Comments: The `#` prefix is recognized by the lexer (lexer.cpp:111) and the rest of the line is consumed without emitting any token. Inline comments (`echo hi # trailing`) work the same way. `#` never reaches the dispatcher.
tsrvd back to top ↑launch and supervise tsrvd server worker processes
tsrvd start <port> [handler] [/stream] [/dll:<path>] [/workers:N] [/norestart]
tsrvd status <id>
tsrvd stop <id>
tsrvd list
tsrvd recv|send|close <conn> (only inside a /stream handler)
Runs the multithreaded TCP server in a SEPARATE process (tsrvd.exe), with cshw as the master: cshw launches the worker, supervises it over a control pipe, and can query its status or stop it. Because the worker is its own process, a crash in the server's network handling cannot take down the shell.
tsrvd.exe is found next to cshw.exe. Each connection the worker accepts is RELAYED to the cshw `handler` proc over a per-connection pipe: the handler receives the request as its argument and its return value is sent back as the response (line-oriented request/response in this version). cshw never touches the socket -- the worker owns it. See also: tcpserver, which runs an in-process server when you want handlers to share the shell's live state directly.
start <port> [handler] [/workers:N] [/norestart]
Launch a worker listening on <port>, relaying each connection to the cshw
proc <handler> (omit it for a no-op server). Blocks until the worker is up.
Sets $result to the new daemon id. /workers caps the worker thread pool.
By default a worker that dies unexpectedly is auto-restarted (with
backoff); /norestart disables that.
Example handler (echoes the request back):
proc my_handler(req)
return "got: $req"
endproc
tsrvd start 8080 my_handler
status <id>
Query the worker and print its STAT line:
STAT <accepted> <active> <running>
(total connections accepted, currently active, and 1 if listening).
Also sets $result to that line.
stop <id>
Ask the worker to stop; if it overstays it is terminated. Removes it
from the list.
list
Show all launched workers: id, port, pid, state (running/dead/failed),
restart count (RST), and the last STAT seen.
By default the handler is request/response: handler(request) -> return response,
one exchange per connection. With /stream the handler instead DRIVES the
connection -- it is called as handler(conn) and uses proxied socket ops over the
per-connection pipe for a multi-message conversation:
proc chat(conn)
while 1
tsrvd recv $conn # sets $result; $? != 0 at end of stream
if $? != 0
break
endif
tsrvd send $conn "echo:$result"
end
tsrvd close $conn
endproc
tsrvd start 8087 chat /stream
recv/send/close operate on the <conn> handle the handler is given; they are only
meaningful inside a /stream handler. The socket still lives in the tsrvd worker;
cshw only exchanges request/response bytes over the pipe.
Instead of a cshw handler, a worker can load a native handler DLL that owns the
protocol end to end:
tsrvd start 8080 /dll:http.dll
cshw never sees the connections in this mode -- it only launches and supervises
the worker (status / stop / auto-restart still apply). The DLL implements the
stable C ABI in tsrvd_plugin.h: TsrvdAbiVersion, TsrvdInit, TsrvdOnConnection
(called per connection on a worker thread), TsrvdShutdown. tsrvd hands each
connection a small vtable (recv/send/close/peer/stopping); the plugin links
nothing of tsrvd. Reference plugins: echo.dll (byte echo), http.dll (HTTP/1.1 +
HTTP/2 static-file + CGI web server, HTTPS via TLS; HTTP/3 is the separate
quicsrv worker), smtp.dll (full ESMTP server: AUTH PLAIN/LOGIN, STARTTLS, maildir/mbox
delivery -- see smtp.conf.example), ftp.dll (FTP server: login/anonymous,
passive+active, browse/download and optional writes, sandboxed to a root -- see
ftp.conf.example), and pop3.dll (POP3 server with STLS that serves the smtp
per-user spool, so clients retrieve received mail -- see pop3.conf.example). The
DLL is found next to tsrvd.exe, or give a full path.
Plugin config goes through /dllcfg:<file>, e.g.
tsrvd start 25 /dll:smtp.dll /dllcfg:smtp.conf
cshw's `checkmail` builtin / the $mail prompt check can then watch smtp.dll's
per-user spool and announce "You have new mail for user: <name>".
.AUTO-RESTART
A worker that exits unexpectedly is relaunched automatically, with increasing
backoff. If it crash-loops (too many restarts in a short window) it is marked
'failed' and left alone (visible in `tsrvd list`); `tsrvd stop <id>` clears it.
Use /norestart on `start` to opt out.
# Launch an isolated server on 8080, check it, then stop it
tsrvd start 8080
set sid $result
tsrvd status $sid
tsrvd stop $sid
# See everything that's running
tsrvd list
If cshw exits, its control pipes close and each worker detects the master is gone and stops itself -- so workers are not orphaned.
0 Success >0 Error (worker not found, failed to launch, etc.)
type back to top ↑display file contents
type FILE...
type FILE | command
Displays the contents of one or more files to standard output. Similar to the UNIX 'cat' command, type is used for viewing file contents, concatenating files, and feeding file contents into pipelines.
When multiple files are specified, their contents are displayed sequentially, effectively concatenating them.
FILE One or more files to display.
type readme.txt
Display contents of readme.txt.
type file1.txt file2.txt
Display contents of both files sequentially.
type log.txt | grep error
Pipe file contents to grep for filtering.
type config.ini | head 20
Show first 20 lines of a config file.
type *.txt
Display contents of all text files.
type data.csv | wc -l
Count lines in a CSV file.
type script.csh | grep "proc "
Find procedure definitions in a script.
0 Success 1 File not found 2 Access denied or read error
Binary Files: Type is designed for text files. Displaying binary files will produce garbled output and may affect your terminal.
Large Files: For large files, consider using 'head' or 'tail' to view portions, or pipe through 'grep' to find specific content.
Encoding: CSHW's type command handles UTF-8 and UTF-16 encoded files automatically. For other encodings, output may appear incorrect.
Piping: Type is frequently used as the start of a pipeline to feed file contents into other commands like grep, sort, wc, etc.
umask back to top ↑set file creation mode mask
umask
umask MASK
Displays or sets the file creation mode mask. The umask value is subtracted from the default permissions when creating new files.
On Windows, umask has limited effect since Windows uses ACLs rather than UNIX-style permissions.
MASK Octal permission mask (e.g., 022, 077).
umask
Display current umask value.
umask 022
Common umask: files 644, directories 755.
umask 077
Restrictive: only owner can access new files.
umask 002
Group-friendly: files 664, directories 775.
0 Success
How umask Works: Default permissions minus umask equals actual permissions. File default: 666 (rw-rw-rw-) umask: 022 Result: 644 (rw-r--r--)
Directory default: 777 (rwxrwxrwx) umask: 022 Result: 755 (rwxr-xr-x)
Common Values: 022 Standard user (owner full, others read) 077 Private (owner only) 002 Collaborative (group full) 000 No mask (full permissions)
Windows Limitations: Windows doesn't use UNIX permissions natively. umask affects: - Files created by POSIX-compatible operations - Cygwin/MSYS interoperability - Cross-platform script behavior
Persistence: umask affects only the current shell. Set in startup scripts for persistence.
unalias back to top ↑remove command aliases
unalias NAME
unalias NAME...
unalias -a
Removes one or more previously defined command aliases. After removal, the alias name will no longer expand to its defined command.
NAME Alias name(s) to remove.
-a, --all Remove all defined aliases.
unalias ll
Remove the 'll' alias.
unalias ll la ls
Remove multiple aliases.
unalias -a
Remove all aliases.
alias g=grep
g pattern file.txt # Works
unalias g
g pattern file.txt # Error: g not found
0 Success 1 Alias not found
Non-existent Aliases: Removing an alias that doesn't exist may produce a warning but is not a fatal error.
Persistence: Like aliases, unalias changes only affect the current session. To permanently remove an alias, edit your startup script.
Restoring Commands: If you aliased over a built-in command, unalias restores access to the original command.
uname back to top ↑print system information
uname
uname [options]
Displays system information including operating system name, version, machine architecture, and more. Provides UNIX-compatible system identification on Windows.
-a, --all Print all information.
-s, --kernel-name
Print operating system name.
-n, --nodename Print network node hostname.
-r, --kernel-release
Print kernel/OS release.
-v, --kernel-version
Print kernel/OS version.
-m, --machine Print machine hardware name (architecture).
-p, --processor Print processor type.
-o, --operating-system
Print operating system name.
uname
Print OS name (Windows_NT).
uname -a
Print all system information.
uname -m
Print architecture (x86_64 or ARM64).
uname -r
Print OS version/build.
uname -n
Print computer name.
0 Success
Output Format: With -a, output is: OS nodename release version machine processor
Windows Values: - OS: Windows_NT - Machine: x86_64 (AMD64) or ARM64 - Release: Windows version (e.g., 10.0.19045)
Cross-Platform Scripts: uname allows scripts to detect the operating system: if ($(uname -s) == "Windows_NT") echo "Running on Windows" endif
Comparison: - uname: UNIX-style system info - winver: Windows-specific version details - version: CSHW shell version
unbindevent back to top ↑remove a window event binding
unbindevent <hwnd> <kind> [<args>]
Removes a binding previously installed by `bindevent`. The kind and per-kind args identify which binding to remove (same key shape as `bindevent`). Removing a binding that doesn't exist is a clean no-op.
<hwnd> Target HWND. (IsWindow() is NOT required here -- removing
a binding from a destroyed window is allowed.)
<kind> Same kinds as `bindevent`. Per-kind args identify
command/notify/timer/keydown bindings; close/destroy/
lbutton/size take no extras.
unbindevent $w command 100
unbindevent $w close
unbindevent $w keydown 27 # remove the Esc-key handler
0 Success (including the no-op case). 1 Bad HWND syntax, unknown kind, or missing args.
uncomplete back to top ↑remove tab completion rules
uncomplete COMMAND
uncomplete COMMAND...
Removes custom tab completion rules for commands, reverting to default file completion behavior.
COMMAND Command(s) to remove completion rules for.
uncomplete cd
Remove custom cd completion.
uncomplete git svn hg
Remove completion for multiple commands.
complete cd d
# Tab after cd shows only directories
uncomplete cd
# Tab after cd now shows files too
0 Success 1 No rule defined for command
Effect: After uncomplete, the command uses default file completion.
Use Cases: - Reset unwanted completion behavior - Debug completion issues - Temporarily disable custom completion
unfileblob back to top ↑decode a fileblob back into a file
unfileblob [blob] [outfile]
unfileblob reverses fileblob: it takes a CSHWBLOB1 text blob and writes the decoded bytes back out as a file.
The blob may be supplied as an argument -- typically a shell variable holding one -- or piped in on standard input. If <outfile> is given it is used as the destination; otherwise the original filename embedded in the blob is used.
unfileblob "$logo" icon.png
Decode a blob held in a variable to a named file.
unfileblob < icon.blob
Decode a saved blob file, restoring the original filename.
0 on success; non-zero if the input is not a valid fileblob or the output file cannot be written.
unhash back to top ↑remove command from hash table
unhash COMMAND
unhash COMMAND...
Removes one or more commands from the hash table cache. Next time the command is run, the shell will search PATH to find it.
COMMAND Command name(s) to remove from cache.
unhash python
Remove python from cache.
unhash git python node
Remove multiple commands.
# After replacing a program with new version:
unhash myprogram
myprogram # Now finds the new version
0 Success 1 Command not in hash table
Use Cases: - Force shell to find updated program location - Clear cache for specific command - Debug command resolution issues
vs rehash: - unhash: Removes specific entries - rehash: Rebuilds entire table
After unhash, the command is looked up in PATH on next execution and potentially re-added to the hash.
uniq back to top ↑report or filter out repeated lines
uniq [options] [FILE]
sort FILE | uniq
Filters adjacent matching lines from input. Typically used after sort to remove or count duplicate lines.
Note: uniq only removes ADJACENT duplicates. Sort input first to remove all duplicates, or use 'sort -u'.
FILE File to process (default: stdin).
-c, --count Prefix lines with occurrence count.
-d, --repeated Only print duplicate lines.
-u, --unique Only print unique lines (appears once).
-i, --ignore-case
Ignore case when comparing.
sort names.txt | uniq
Remove all duplicate lines.
uniq -c sorted.txt
Count occurrences of each line.
sort data.txt | uniq -d
Show only duplicated lines.
sort data.txt | uniq -u
Show only lines that appear once.
dir /b | sort | uniq
List unique filenames.
type log.txt | grep ERROR | sort | uniq -c
Count unique error messages.
0 Success 1 Error
Important: Sort First! uniq only compares adjacent lines. To remove all duplicates: sort file.txt | uniq
Or use: sort -u file.txt
Counting: The -c option is useful for frequency analysis: cat access.log | cut -d' ' -f1 | sort | uniq -c | sort -rn
unlimit back to top ↑report that resource limits cannot be removed
unlimit
unlimit RESOURCE
Accepted for tcsh compatibility. IT REMOVES NOTHING, because there is nothing to remove: Windows has no per-process rlimit that a shell can raise or drop. unlimit prints where the figures `limit` reports actually come from and exits 0.
Earlier versions of this page described raising soft limits toward hard limits and a permission-denied exit code for the attempts that failed. No such mechanism exists here, and no attempt is made.
RESOURCE Accepted and ignored. See `limit` for the list of
resources that can be reported.
unlimit
Print the explanation.
unlimit filesize
The same. The resource name changes nothing.
0 Always. Nothing was attempted, so nothing can fail.
Why: UNIX rlimits are per-process kernel state a program can adjust for itself. The Windows equivalent is the Job Object, which is applied to a process from outside and governs the whole job. A shell cannot lift its own ceiling, so `unlimit` has nothing to act on.
What to use instead: Nothing in cshw constrains a child process by default, so there is generally nothing in the way. If a program needs MORE than the system allows -- more handles, a bigger stack -- that is set in the program's own PE header or manifest, not by the shell that launches it.
Reporting: `limit` with no argument prints every resource, this process's usage, and system memory. That is the useful half of this pair.
unregistercmdlib back to top ↑unregister command library (unload plugin DLL)
unregistercmdlib PATH|NAME|PREFIX
unregistercmdlib /all
urcl PATH|NAME|PREFIX
urcl /all
Alias for urcl. See 'man urcl' for full documentation.
unset back to top ↑remove shell variables
unset NAME
unset NAME...
Removes one or more shell variables from the current environment. After unsetting, the variable is no longer defined and references to it will return empty values.
NAME One or more variable names to remove.
unset count
Remove the variable 'count'.
unset var1 var2 var3
Remove multiple variables.
set temp="temporary"
echo $temp
unset temp
echo $temp
# Second echo outputs nothing
0 Success 1 Variable not found (may still succeed)
Non-existent Variables: Unsetting a variable that doesn't exist is not an error.
Environment Variables: unset removes shell variables. To remove environment variables, use 'unsetenv' instead.
Special Variables: Some special variables ($?, $:, $$) cannot be unset as they are managed by the shell.
Scope: unset only affects variables in the current shell scope. Variables in parent or child processes are not affected.
unsetenv back to top ↑remove environment variable
unsetenv NAME
unsetenv NAME...
Removes one or more environment variables from the current process environment. Child processes will not inherit the removed variables.
NAME Environment variable name(s) to remove.
unsetenv DEBUG
Remove DEBUG variable.
unsetenv TEMP_VAR MY_CONFIG
Remove multiple variables.
setenv TEST_VAR "hello"
echo %TEST_VAR%
unsetenv TEST_VAR
echo %TEST_VAR%
# Second echo shows empty
0 Success 1 Error
System Variables: Some system variables (PATH, SYSTEMROOT, etc.) should not be unset as they may affect system operation.
Scope: unsetenv only affects the current process and its future children. It does not affect: - The parent process - Other running programs - System environment (permanent settings)
Verification: Use 'env' or 'printenv' to verify the variable was removed.
unshadow back to top ↑restore a built-in hidden by shadow
unshadow COMMAND ...
unshadow -a
Puts a built-in back into command lookup after `shadow` took it out. The command was never destroyed, only set aside, so this always succeeds for anything `shadow` hid.
COMMAND A shadowed built-in to restore. Several may be
named at once.
-a, --all Restore every shadowed built-in.
unshadow tree
Give `tree` back to the built-in.
unshadow -a
Restore everything. Worth knowing when a startup script has
shadowed more than its author remembers; `shadow` with no
arguments lists what that is.
0 Every named command was restored. 1 At least one name was not shadowed to begin with.
Only what shadow hid: A plugin loaded with `rcl` also displaces an intrinsic of the same name, and that one belongs to `urcl`. unshadow will not restore it, and says the name is not shadowed -- the two mechanisms share a store, so keeping them apart is what stops `unshadow` from pulling a command out from under a loaded plugin.
unzip back to top ↑extract or list a .zip archive
unzip [/l] [/d:<dir>] [/p[:<password>]] <archive.zip>
Extract a .zip archive, or list its contents without extracting. Supports password-encrypted archives via /p.
/l, /list, --list
List archive contents instead of extracting. Prints entry
names, sizes, and last-modified timestamps.
/d:<dir>, --dest:<dir>
Extract into <dir> rather than the current directory. The
directory is created if it doesn't exist.
/p[:<password>]
Password for encrypted archives. Bare /p prompts on the
console; /p:<value> uses the literal password.
<archive.zip>
Archive to extract or list.
unzip backup.zip
Extract everything into the current directory.
unzip /l backup.zip
List archive contents.
unzip /d:out backup.zip
Extract into out/.
unzip /p:s3cret secret.zip
Extract a password-protected archive.
0 Extraction or listing succeeded. 1 Bad arguments, archive not found, wrong password, or I/O error.
uptime back to top ↑show how long system has been running
uptime
Displays the current time, how long the system has been running, and system load information.
uptime
Display system uptime.
0 Success
Output includes: - Current time - Time since last boot (days, hours, minutes) - Number of logged-in users (if available)
Windows Uptime: On Windows, uptime is calculated from the system boot time. This can also be viewed in Task Manager's Performance tab.
Long Uptimes: Servers often have uptimes measured in weeks or months. Desktops typically restart more frequently for updates.
urcl back to top ↑unregister command library (unload plugin DLL)
urcl PATH|NAME|PREFIX
urcl /all
unregistercmdlib PATH|NAME|PREFIX
unregistercmdlib /all
Unloads a previously registered command library and removes all its commands from the shell.
The library can be identified by its DLL path, library name, or namespace prefix.
If the library had shadowed any intrinsic commands, those built-in commands are restored when the library is unloaded.
The plugin's UnregisterCommandLibrary function is called (if exported) to allow cleanup before the DLL is freed from memory.
PATH|NAME|PREFIX Identify library by DLL path, name, or prefix.
/all Unload all command libraries.
/a Short form of /all.
urcl mylib
Unload library by its prefix or name.
urcl C:\Plugins\mylib.dll
Unload library by its DLL path.
urcl /all
Unload all loaded command libraries.
0 Success 1 Library not found
Cleanup: Before unloading, the shell calls UnregisterCommandLibrary if the DLL exports it. Use this to release resources, close handles, etc.
Restoration: If the library had shadowed built-in commands (e.g., provided its own "echo" command), the original intrinsic commands are automatically restored when the library is unloaded.
Order: When unloading all libraries with /all, they are unloaded in arbitrary order. Design plugins to not depend on unload order.
vartype back to top ↑display variable type
vartype NAME
vartype $NAME
Displays the data type of a shell variable. CSHW automatically tracks variable types based on assigned values, supporting strings, integers, and floating-point numbers.
NAME Variable name to examine (with or without $).
set count=42
vartype count
# Output: integer
set name="John"
vartype name
# Output: string
set pi=3.14159
vartype pi
# Output: float
set hex=0xFF
vartype hex
# Output: integer
0 Success 1 Variable not found
Type Inference: CSHW infers types automatically: - Integer: whole numbers (42, -17, 0xFF, 0b1010) - Float: numbers with decimals (3.14) or exponents (1e-3) - String: everything else
Type Conversion: Variables can change type when reassigned: set x=42 # integer set x="hello" # now string
Type in Expressions: Type matters in expressions. String comparisons use lexicographic order, numeric comparisons use numeric order.
ver back to top ↑display shell version (alias for version)
ver
-s, --short Print just the version number, for scripts.
`ver` is identical to `version`. See `man version` for details.
version back to top ↑display shell version
version
ver
Aliases: ver
Displays the CSHW shell version number and build information.
version
Display shell version.
ver
Short form (alias for version).
0 Success (always)
The version command shows the CSHW version. For Windows version information, use 'winver' instead.
vol back to top ↑display a volume's label and serial number
vol [DRIVE:]
Prints the volume label and serial number of a drive, in the wording cmd.exe uses -- scripts that grep this output are the reason to match it rather than improve it.
With no argument, reports the volume holding the CURRENT DIRECTORY. That is resolved with GetVolumePathName rather than by slicing off the first two characters, so it is right on a mapped drive and on a directory mounted into another volume's namespace.
DRIVE: Drive to report. A path works too: `vol .` and
`vol C:\some\mount\point` both name the volume that
actually holds them.
vol
The volume holding the current directory.
vol D:
A named drive.
vol \\server\share
A UNC path. There is no drive letter, so the share is named
instead of printing a stray colon.
0 The volume was read 1 No such drive, or its information could not be read
A volume with no label prints "has no label." rather than an empty name, which is what cmd.exe does and what a script testing for a label expects to see.
wait back to top ↑Wait for all running coroutines (alias for `cowait /all`).
No detailed man page yet — see the one-line summary above.
watch back to top ↑execute command periodically
watch COMMAND
watch -n INTERVAL COMMAND
watch [options] COMMAND
Executes a command repeatedly at regular intervals, displaying the output. Useful for monitoring changes over time. Press Ctrl+C to stop.
COMMAND Command to execute repeatedly.
-n INTERVAL Seconds between executions (default: 2).
-d, --differences
Highlight differences between updates.
-t, --no-title Don't show header with time and command.
-e, --errexit Exit on command error.
watch dir
Monitor directory changes every 2 seconds.
watch -n 5 processlist
Show process list every 5 seconds.
watch -n 10 df
Monitor disk space every 10 seconds.
watch -d "dir /b"
Highlight file changes.
watch -n 1 "type log.txt | tail -10"
Monitor last 10 lines of log.
watch "grep ERROR log.txt | wc -l"
Count errors continuously.
0 Exited normally (Ctrl+C) 1 Error running command 2 Invalid arguments
Display: watch clears the screen and shows fresh output each interval. The header shows current time and the command being run.
Quoted Commands: For commands with pipes or multiple arguments, use quotes: watch "ps | grep python"
Interval: Minimum interval is typically 0.1 seconds. Very short intervals can cause high CPU usage.
Use Cases: - Monitor log files for new entries - Watch process status changes - Track disk space - Observe build progress - Check network connectivity
Stopping: Press Ctrl+C to stop watching.
wc back to top ↑word, line, character, and byte count
wc [options] FILE...
command | wc [options]
Counts lines, words, characters, and bytes in files or standard input. By default, displays all counts. Options allow selecting specific counts.
FILE One or more files to count.
-l, --lines Print only line counts.
-w, --words Print only word counts.
-c, --bytes Print only byte counts.
-m, --chars Print only character counts.
wc file.txt
Show lines, words, and bytes for file.txt.
wc -l file.txt
Count only lines.
wc -w document.txt
Count only words.
wc *.txt
Count for all text files (with totals).
dir /b | wc -l
Count number of files in directory.
find . -name "*.cpp" | wc -l
Count number of C++ files.
type log.txt | grep error | wc -l
Count error lines in log.
wc -l -w report.txt
Show both line and word counts.
0 Success 1 File not found 2 Read error
Output Format: Default output shows: lines words bytes filename With multiple files, a total line is added.
Words: A "word" is defined as a sequence of non-whitespace characters separated by whitespace.
Characters vs Bytes: For ASCII text, -c and -m give the same result. For UTF-8 encoded files, -m counts Unicode characters while -c counts bytes.
Common Uses: - Count lines in a file: wc -l file.txt - Count files: dir /b | wc -l - Measure code: wc -l *.cpp *.h
where back to top ↑locate every place a command name resolves
where NAME
where /R DIR NAME
Reports every place NAME resolves, in the order the dispatcher actually consults them: shell procedure, then alias, then built-in, then each directory of PATH. 'which' stops at the first answer; 'where' shows all of them, which is what makes it the tool for "why am I getting THAT one".
For the PATH search, NAME is tried bare and then with each of the executable extensions .exe, .com, .bat, .cmd and .ps1. The current directory is searched before PATH.
With /R, a directory tree is searched instead of PATH, using the same extension list.
NAME Exact command or file name to locate. NOT a pattern --
see WILDCARDS below.
/R DIR Search the tree under DIR instead of PATH.
/r is accepted too.
where notepad
# C:\windows\system32\notepad.exe
# C:\windows\notepad.exe
where pwd
# pwd: shell procedure
# pwd: cshw built-in command
Shows that a procedure is shadowing the built-in.
where /R C:\Tools mytool.exe
Search the C:\Tools tree for mytool.exe.
0 At least one match found 1 No matches found
Wildcards: NOT supported. NAME is matched exactly (case-insensitively, plus the extension list) -- there is no globbing inside where. Earlier versions of this page advertised `where *.exe` and `where java*`; neither ever worked. Note also that the SHELL expands the pattern before where is invoked, so `where *.exe` usually fails with "No match." from the globber and where itself never runs at all.
Repeated results: where reports one hit per PATH entry, and does not deduplicate. If the same directory appears in PATH three times, its match is printed three times. That is faithful -- it is showing what PATH actually says. The same goes for entries differing only in case: C:\windows and C:\WINDOWS are two separate entries and produce two separate lines.
Which one runs: The first line is what would execute if you typed the name:
proc > alias > built-in > PATH
An alias beats a built-in, as it does in tcsh and bash -- that is what makes `alias ls 'ls -l'` do anything. A procedure beats both; csh has no functions so tcsh never had to rank them, and cshw puts its own on top.
The order here is not decoration. The whole promise of this command is that the first line is the winner and the rest are shadowed, so it has to match what the dispatcher does or it is worse than saying nothing.
/R and reparse points: The recursive walk does not follow junctions or symbolic links. A reparse point aimed at one of its own ancestors would otherwise make the walk re-enter the same subtree indefinitely -- and the standard example ships on every Windows install, since each user profile has AppData\Roaming\Application Data pointing straight back at AppData\Roaming. The consequence to know about: a file reachable only through a junction is not reported. Search the link's target directly.
/R and long paths: The walk is not limited to MAX_PATH (260 characters). It searches in the extended-length namespace internally, so files nested deeper than that are found and reported normally. The internal \\?\ prefix never appears in output.
This applies to the /R walk specifically. Other commands that take a path are still subject to the 260-character limit.
/R cost: /R is a full recursive enumeration with no index behind it. Pointing it at a large tree is genuinely slow: searching all of C:\Windows means walking roughly 700,000 entries and takes the better part of a minute. Point it at the narrowest directory that could hold what you are looking for.
which back to top ↑locate a command
which COMMAND
which COMMAND...
Displays the full path of the executable that would be run for each COMMAND. Searches through the PATH environment variable to find the first matching executable.
COMMAND Command name(s) to locate.
which notepad
# C:\Windows\System32\notepad.exe
which python
# C:\Python311\python.exe
which git
# C:\Program Files\Git\cmd\git.exe
which grep
# (built-in) - for CSHW built-in commands
which notepad python
Locate multiple commands.
which nonexistent
# Command not found
0 Command found 1 Command not found
Search Order: 1. Built-in shell commands 2. Aliases 3. PATH directories (left to right)
Executables: On Windows, which looks for files with executable extensions: .exe, .com, .bat, .cmd, .ps1
Built-in Commands: For built-in commands, which indicates "(built-in)" instead of a file path.
Multiple Matches: which shows only the first match, in the order the dispatcher resolves names:
proc > alias > built-in > PATH
Use 'where' to see all of them. An alias beats a built-in, so a name that is both is reported as the alias -- that is what actually runs.
Shadowed built-ins: A built-in hidden with `shadow` is NOT reported as a built-in, because it is no longer what runs. which reports whatever PATH turns up instead, with the reason appended:
which tree tree: cshw built-in command shadow tree ; which tree C:\Windows\System32\tree.com (shadowed intrinsic)
Case Sensitivity: Command names are case-insensitive on Windows.
whoami back to top ↑display current user name
whoami
whoami [options]
Displays the user name of the current user. On Windows, shows the username in DOMAIN\username format.
/upn Display the User Principal Name (user@domain).
/fqdn Display the fully qualified DN.
/user Display the account name and its SID.
/groups Display groups the user belongs to.
/priv Display user privileges.
/all Display all available information.
/user, /upn and /fqdn each REPLACE the default DOMAIN\user line
rather than adding to it, the same way Windows' own whoami.exe
treats them. /groups, /priv and /all add to it.
whoami
Display current username.
whoami /groups
Show group memberships.
whoami /priv
Show user privileges.
whoami /all
Display comprehensive user information.
0 Success 1 Error
Administrator Check: To check if running as Administrator, look for BUILTIN\Administrators in 'whoami /groups' output.
Domain vs Local: On domain-joined machines, shows the domain name. On standalone machines, the computer name.
/upn and /fqdn need a domain: Both names exist only for a domain account. On a workgroup machine whoami says so and exits 1, rather than printing the down-level DOMAIN\user name and letting it pass for a UPN -- which is what all three of these options used to do.
winapi back to top ↑call a Win32 API by name with auto-resolution of its DLL
winapi [-d] [-v] [-h] FUNCTION [ARGS...]
Sugar layer over rundllproc. Looks FUNCTION up in cshw's built-in table of common Win32 APIs, resolves the hosting DLL (kernel32, user32, gdi32, advapi32, shell32, ole32, ws2_32, ...) and picks the W or A variant appropriate to cshw's wide-char default, then dispatches the existing rundllproc command.
Most callers never have to remember which DLL exports a function. For unusual cases (private DLL, ordinal lookup, non-standard signature) use rundllproc directly.
-d, --dump Print the resolved <dll>::<name> and exit.
Useful for verifying which export will be called.
-v, --verbose Forwarded to rundllproc; prints handle and args.
-h, --help Show built-in help.
FUNCTION Win32 API name. Bare name picks the W variant
by default for W/A pairs; append A or W to force
a specific variant (MessageBoxA vs MessageBox).
ARGS Arguments forwarded verbatim to rundllproc.
winapi GetTickCount
kernel32::GetTickCount -- no arguments, no W/A variant.
winapi Sleep 250
kernel32::Sleep called with a 250 ms delay.
winapi MessageBox 0 "hi" "cshw" 0
Resolves to user32::MessageBoxW. The bare name picks W.
winapi MessageBoxA 0 "hi" "cshw" 0
Forces the ANSI variant.
winapi -d CreateWindow
Prints "user32.dll::CreateWindowW" without calling anything.
winapi -v GetSystemDirectory
Verbose call, shows DLL handle and arg marshalling.
0 Success (the function returned; the value is in $?).
1 Function name not in table and no user override; or the
underlying rundllproc call failed.
2 Syntax error (no function name, unknown option).
Extending the table: A user-level TSV at %APPDATA%\cshw\winapi.tsv adds or overrides entries: FunctionName<TAB>your.dll<TAB>None|W|A Lines beginning with '#' are comments. User entries win over built-ins, so this is also the way to remap a name to a different DLL.
Resolution order: 1. Exact name match in user TSV. 2. Exact name match in the baked-in table. 3. Strip a trailing W or A and retry (so CreateWindowA finds the CreateWindow entry and dispatches the literal name you typed). 4. Friendly error suggesting rundllproc and the TSV path.
W vs A: For functions that exist as a W/A pair, the table records the bare name and a default variant (almost always W). Type the suffix explicitly to override per-call without editing the table.
Safety: winapi inherits rundllproc's crash semantics. Wrong argument count or type can crash the shell. Prefer -d first to confirm resolution before chaining a call into a script.
winver back to top ↑display Windows version
winver
-s, --short Print just the version number, for scripts.
Displays detailed information about the currently running Windows version, including edition, version number, and build information.
winver
Display Windows version information.
0 Success
Information Displayed: - Windows edition (Home, Pro, Enterprise, etc.) - Version number (e.g., 22H2) - Build number (e.g., 19045.3803) - Architecture (32-bit or 64-bit)
Version vs Build: - Version: Marketing version (21H2, 22H2, 23H2) - Build: Specific build number, changes with updates
For CSHW shell version, use 'version' or 'ver' instead.
writefile back to top ↑write a shell variable's contents to a file
writefile <variable> <file>
writefile writes the contents of shell variable <variable> out to <file>, overwriting any existing file. It is the inverse of readfile.
The variable's text is written as-is; a trailing newline appears only if the variable's value already ends with one. The file is written as text, so LF line endings become CRLF.
writefile report summary.txt
Save $report to summary.txt.
readfile data in.txt
writefile data out.txt
Copy a file's contents through a variable.
0 on success; non-zero if the variable is not set or the file cannot be written.
xargs back to top ↑build command lines from standard input and run them
xargs [options] [command [initial-args...]]
xargs reads items from standard input and runs <command> with those items appended as arguments. It is most often used at the end of a pipe to turn a list of names into arguments for another command:
ls *.tmp | xargs rm
If no <command> is given, echo is used. Input items are separated by whitespace (spaces, tabs, newlines) unless -0 or -d changes that. Without -n or -I, every item is passed to a single invocation.
Options: -n N pass at most N items to each invocation -I STR replace STR in the command with one input item, running the command once per input line -d C use character C as the item separator -0 items are separated by NUL (for `find -print0`) -t print each command line to stderr before running it -r do not run the command if the input is empty (long form: --no-run-if-empty)
ls *.log | xargs rm
echo a b c | xargs -n 1 echo
cat filelist.txt | xargs -I F cp F backup/
0 if every invocation succeeded, 1 if any invocation reported failure.
zip back to top ↑create a .zip archive (Windows-style)
zip [/r] [/p[:<password>]] <archive.zip> <file_or_dir> [more...]
Creates a .zip archive from the listed files and/or directories. Existing archives are overwritten. Entry paths inside the archive use forward slashes and are relative to each argument's leaf name (so `zip pkg.zip src` produces entries `src/...`, not absolute paths).
Supports password protection with AES-256 encryption via /p.
/r, --recursive
Recurse into subdirectories when an argument is a directory.
/p[:<password>]
Encrypt entries with AES-256. Bare /p prompts on the console
with confirm. /p:<value> uses the literal password (suitable
for scripts; note the password ends up in process args and
shell history).
<archive.zip>
Output path. Overwritten if it exists.
<file_or_dir>...
One or more inputs. Mix of files and directories ok.
zip backup.zip src docs README.md
Bundle two directories + a file.
zip /r site.zip public
Recursively archive the public/ tree.
zip /p:s3cret secret.zip notes.txt
Encrypted with literal password.
zip /p secret.zip notes.txt
Encrypted; prompts for password on the console.
0 Archive created. 1 Bad arguments or I/O error (see stderr).
The Windows-style `zip` builds ZIP archives. For tar/tar.gz/tar.bz2, see `tar`. To extract or list, see `unzip`.