See README.txt as well. It tells you how to build brash from the source code.
Updated: 02/16/2016
BRASH
=====
Brash is a bourne shell clone written using threads instead of fork/exec. It has
many bash-like features, particularly the keyboard handling, and will eventually
evolve to become more like bash. Brash has a variety of unix commands built into
it as well. These commands always begin with a leading '.' character to let
you know they are not exact duplicates of the unix command by the same name.
Version 1.1.28 lacks the following bash features:
* array variables
* the tilde character, "~", when used as the leading part of a filename,
works -- but only for the current user. The ~username/ syntax is not
supported.
* the keyboard handling lacks the depth of bash's configurability, but
is fairly full featured. See "Console Window Edit Keys", below.
* the set command is very limited. Use the command "builtins" to get a list
of what is supported.
* shopt
* bg ( the & operator works to execute commands in the background )
* caller
* enable
* env only lets you list the environment, not manipulate it
* exec
* help
* history (instead use fc -l range...)
* the jobs command is very limited
* local
* mapfile ( but read -f can simulate )
* printf
* readarray
* readonly
* set has limited options
* suspend
* test ( though [ expression ] does work )
* times
* trap
* typeset
* umask
* ulimit
* wait
Brash understands the Windows file naming convention and lets you use it they
it was meant to be used -- in a case insensitive manner. It also interprets
forward slash in file names as if they were two backlashes -- especially
when you use the Tab-completion feature of the console.
For help, use "brash -h".
WHY BRASH
=========
Of course, you could just use CYGWIN. But the source code for GNU bash requires
the full GNU unix simulation of fork/exec and all the libraries and dlls to
install.
Brash is a single executable with no other libraries and tools to install.
To install brash, you technically only need the brash.exe file. But in practice,
having a well thought out .brashrc file will be immensely helpful. Brash also
includes a few builtin-commands, see below, that allow you to use linux-like
directory listings, file printing, etc: ".ls", ".cat", ".regex".
Brash's console reader, though which you enter commands, understands the nature
of both unix style file names and microsoft windows filenames. And since you
are on windows, the TAB-completion function generates microsoft filenames -- which
contain backslashes instead of forward slashes. And since backslash is an
escape character in brash, the directory separator is a double backslash to
the tab-completion feature.
This feature is not perfect, however. If you have directories
with spaces in the names, it is not as perfect as would be desirable. Still it
works most of the time, and does understand spaces in filenames starting with the
current directory.
Another way that brash reduces the need to download the entirety of the GNU
tools package is that it provides several new builtin commands that behave, in
most key ways, like the very important unix command line tools that are often used
in writing scripts. See "DIFFERENCES WITH BASH / BOURNE SHELLS".
The source code for brash is available on the web and it is written in the normal
multithreading style for Microsoft Windows. You can thus add your own builtin
commands -- and additional syntaxes, if needed.
COPYRIGHT
=========
Brash is mostly copyrighted with my personal copyright, but parts of it are covered
by the GNU General Public License as published by the Free Software Foundation
version 2. This copyright applies to 3 things:
GNU regex.c and .h
GNU fnmatch.c
GNU parse_date.c
My copyright is as follows:
Copyright 2002-2015, Lowell Boggs Jr.
This file or directory, containing source code for a computer program,
is Copyrighted by Lowell Boggs, Jr. 987 Regency Drive, Lewisville
TX (USA), 75067. You may use, copy, modify, and distribute this
source file without charge or obligation so long as you agree to
the following:
1. You must indemnify Lowell Boggs against any and all financial
obligations caused by its use, misuse, function, or malfunction.
Further, you acknowledge that there is no warranty of any kind,
whatsoever.
2. You agree not to attempt to patent any portion of this original
work -- though you may attempt to patent your own extensions to
it if you so choose.
3. You keep this copyright notice with the file and all copies
of the file and do not change it anyway except language translation.
You are responsible for enforcing your own compliance with these
conditions and may not use this source file if you cannot agree to the
above terms and conditions.
BRASH BEHAVIOR
==============
Brash only reads .brashrc on startup, not .profile or .bashrc. The .brashrc
file must be placed in the $USERPROFILE directory. If ever ported to linux
or unix, the file will be placed in the $HOME directory.
An example .brashrc should come with your brash.exe executable.
At this time, brash only runs on Microsoft Windows but is not fundamentaly
different than a program that could easily execute on Linux or unix.
In fact, brash is designed using Unix programming techniques as much as
is possible, but implemented using Microsoft Windows environment.
The .brashrc file can be used to suppress the introductory banner
by definiting the variable, BRASH_NO_BANNER,to any non-empty value.
DIFFERENCES WITH BASH / BOURNE SHELLS
-------------------------------------
Brash will evolved to be very similar to bash but at this time it is like a
cross between bash and bourne with a few extras, limitations and gotchas.
Command Line Differences
------------------------
Use "brash -h" get help on the brash command line processing. The "-c"
option is interpreted the same way that brash interprets it but other
than that, things are much different on the command line.
Syntax limitations
-------------------
Brash's syntax is as close to the bourne shell's as possible, but there are
some obvious limitations:
"if" and "while" statements accept only 1 command as the condition, not
multiple as bash does. In bash and the bourne shell, multiple command
condition statements are allowed -- although this feature seems rarely used.
In brash, when multiple command statements must be used to comprise the
condition, the group of statements must be surrounded by curly braces
in order to approximate the bash/bourne behavior.
Bash example:
if command 1 ; command 2 ; command 3;
then
...
fi
Brash example
if { command 1 ; command 2 ; command 3; }
then
...
fi
To be clear: If your condition has only one command, then you do not need the
curly braces.
Command line interaction
------------------------
Brash keyboard interaction is very much like bash's, but it does not have a
"vi" mode, and ^V does not currently do anything. Sending escape sequences
to terminals and printers is not the way things are typically done windows.
See "Console Window Edit Keys", below.
New builtin commands
--------------------
Brash also includes some builtin
commands that mimic common unix command line tools:
brash | |
builtin | |
command | unix command | Notes
============+==================+=========================================
| |
builtins | man brash | Get a list of builtin commands
| |
basename | basename | same as unix, understands MS paths
| |
dirname | dirname | same as unix, understands MS paths
| |
sleep | sleep | sleeps for a number of seconds. parm is float.
| |
.attrib | chmod | Uses the windows command syntax, but isn't
| | recursive. See -h.
| |
.ls | ls | The key features, but not an exact copy
| |
.regex | grep/sed/nl | The key features of each
| |
.cat | cat | The key features
| |
.rm | rm | Not recursive, and won't delete directories
| |
.stat | basename, | Print info about pathnames, including,
| dirname, | file size, time, etc. Designed for use
| stat | with the eval command to get info about
| | files into script variables.
| |
.head | head | print lines at the begining of files
| |
.cut | cut | print fields / columns from files
| |
.expand | expand | expands tabs in files or compresses spaces
| unexpand | to tabs
| |
.date | date | print the date in a user specified format
| |
.diff | diff | compare files and print the minimal change
| | set that would convert the first file to the
| | second.
| |
.wc | wc | Word count
| |
.stopwatch | ? | saves, prints, compares the current time.
| |
.solve | solve | solves sets of simultaneous linear equations
| | using guassian elimination.
| |
.linreg | ? | linear regression, prediction.
Use the -h option to these new commands for more information.
Note that are several builtin commands whose names begin with . which are not
described above. Use builtins to get the list.
Pipe Operator
-------------
One fundamental difference is the pipe operator: in Brash, the right most
pipe member is executed in the current shell not a subshell. So if you want
to truly duplicate bourne's syntax, all the brash pipe's would have be written
like this:
( cmd1 | cmd2 | cmd3 ... | cmdN)
Instead of just
cmd1 | cmd2 | cmd3 ... | cmdN
Because, for brash, cmdN is executed in the current shell not a subshell.
While this makes an important difference, requiring review of all scripts, it
has the signficant advantage of allowing a pipe to populate
the current shell's environment variables with data produced in pipe.
Consider the following pipe. In bourne shell, it is useless:
echo a | read b
In bourne, the "echo a" and the "read b" are done in sub-shells, but in brash,
the variable b will become populated with 'a'.
For example:
type zip | while read zip is location
In bourne shell (and bash) location is undefined, but in brash, location is now
populated with the pathname of zip.exe (on windows).
Given that this is not supposed to work in bourne, and the fact that it would be
very confusing to write a script that set location before
executing the above "type zip" example, it seems unlikely that this minor change in
program logic will actually result in signifcant portability
issues. (Of course, I have been mistaken before -- and will be again.)
For and Select statements
-------------------------
At this time, the for and select statements require the "in" operator.
WRITING SCRIPTS
===============
Writing brash scripts is essentially the same as writing bash scripts.
To create a script, create a file in your PATH somewhere and you have
two choices:
* name the file command.brash
* name the file just command
If the file's name ends in .brash, brash will find it in your path
when you execute a command linke this:
command args
If you chose not to use the .brash extension, you must add a special
command at the top of the file:
#!/usr/bin/brash
Actually, you don't need the /usr/bin/brash part. Just starting the
file with #! is sufficient, but it is customary to use the string
as shown. This approach was used so that there would be at least
some chance that existing bash/bourne scripts will work.
To find the contents of the last parameter to the current command
you can do something like this:
scriptName()
{
: "$@" # do nothing to th all the parameters
echo $_ is the last parameter
}
The colon command does nothing EXCEPT set the last parameter variable.
Bash does this too.
DOH STUPID ...
===============
This is a list of brash annoyances
0. On windows, of course, directory nodes are separated by backslash characters.
This is painful to work with of course in bourne style script language
interpreters because the backslash characters serves the all important role
of "escaping" the character that follows it -- thus protecting it from being
interpreted by brash.
There are some helpful work arounds to this profound annoyance:
* When you press the tab key to complete a partial file name, the
CommandConsole readLine function turns your /'s into pairs of \'s
unless your string begins with apostrophe, in which case it only
replaces it with the 1.
* Get in the habit of using two backslashes to separate pathnames
(unless you are in an apostrophe quoted string... sigh)
* Use the apostrophe character, habitutally, to surround all file names.
Apostrophe doesn't recognize \ slashes as an escape character.
* Learn to use the string substitution feature of the shell variable
expansion to programatically convert the / to \, or \\ to single, as
needed. For example:
${var//\//\\} # in var, replace all / with \
$(var//\\\\/\\} # replace all cases where 2 backslashes are found with 1 backslash
# may to do do this multiple times to get all repetitions in a string
1. On windows, sometimes file or directory names have odd UTF16 encodings
and as a result the sort program gets confused unless someone fixes the
text for it. This means when you do this:
for f in * ; do echo $f ; done | sort
It will usually work, but not always. If the file/directory names have
non-trivial utf16 encodings, sort just hangs. Thanks Microsoft for putting
off the work of fixing your own program on your own operating system to
someone else -- and not also for not providing an option to just sort in
ascii.
brash reads the strings directly from the windows function and writes them
directly to stdout, and thus some sort of hang occurs in sort when a
strangely encoded name is found.
I personally just created a sort function and put it in my $HOME/.brashrc file:
function sort
{
if [ "$#" = 0 ]
then
utf8dec # conflates utf16 to std ascii
else
for f in "$@"
do
if [ -r "$f" ]
then
utf8dec &2
fi
done
fi |
C:/Windows/System32/sort.exe
}
This script conflates the utf encoded text to the normal ascii form --
leaving out the umlauts and other curlycues. See ../bin/utf8dec.cxx for
the source. It gets built automatically.
Of course, you can't use this sort alias if you really do have utf encoded
data to work with.
2. Many standard Windows commands are actually implemented as part of the cmd.exe
program. Here's a list of aliases that are likely to be needed in your .brashrc
alias cls='cmd /c cls'
alias rm='cmd /C rm'
alias mkdir='cmd /C mkdir'
alias rmdir='cmd /C rmdir'
The del command is particularly picky about backslash vs forward slash, so here
is a script that works better with it:
del()
(
for f in "$@"
do
f1="${f//\//\\}" # convert forward slash to backslash
file="${f1//\\\\/\\}" # convert multiple backslash into single
# backslash
cmd /c del "$file"
done
)
The attrib command is implementable like this:
alias attrib='.attrib'
See the next item for an explanation of why.
3. In releases 01.*.*, if-statements and while-statements do not allow
multiple commands in the if clause. But you can use {} or () to group
multiple statements into one for this purpose.
4. In releases 01.*.*, arithmetic operators are limited to
+
-
*
/
%
>
<
==
>=
<=
^
&
|
&&
||
5. Drive letters as commands
In windows, drive letters are used as commands to switch to the drive. For
example,
E:
This command makes drive E the current drive and the current directory on
drive E as the current directory.
Brash does not directly support this behavior because for brash, there is only
a current directory. There is no separate concept of a current drive.
You could hard code, in your .brashrc file, a bunch of helper functions:
function a:
{
pushd a:/
}
function b:
{
pushd b:/
}
But making 26 of them creates quite a clutter in your .brashrc file. Here
is a code fragment that defines only the needed function:
#
# The following code creates functions for all mounted file systems
#
# These functions are named: a:, b:, c:, p:, q:, etc
#
c:() { pushd c:/ ; }
net use |
.regex -m '[A-Z]:' |
while read status local rest
do
# fix up missing status
case "$status" in
*:)
# status was empty
# slide the other fields over 1
# and put unknown in the status
rest="$local $rest"
local="$status"
status="unknown"
;;
esac
case "$status" in
OK)
echo "${local,,}() { echo pushd $local ; pushd $local/; }"
;;
esac
done | read -f cmd
#
# cmd now holds a list of function definitions that create only the needed
# drive letter commands
#
eval "$cmd"
unset cmd
ENVIRONMENT VARIABLES TO USE AND SET
====================================
BRASH_USER_HOME -- either $HOME on unix, or %USERPROFILE% on Windows
BRASH_SHELL -- the name of this executable
BRASH_VERSION -- the current version of this executable
BRASH_PATH_SEPARATOR -- ';' or ':' depending on the os
BRASH_DIR_SEPARATOR -- / or \\ depending on the os
BRASH_SYSROOT -- either C:\\ or / depending on the os
BRASH_OS -- Either MSWindows or unix depding on the os
BRASH_USER -- Either %USERNAME% or your unix user id
BRASH_HOSTNAME -- Either %COMPUTERNAME or your unix hostname
BRASH_NO_BANNER -- suppress 'welcome screen' at the console
PS1 -- the text of the command prompt. The following special character sequences
are interpreted:
\w: The name of the current directory
\W: The basename of the current directory
\s: The basename of the brash executable that you are running. Usually brash.exe,
\u: the current user name
\h: The first node of the hostname. e.g. "node" in node.domain.company.com
\H: The full hostname
\#: The command history size.
CONSOLE WINDOW COMMAND KEYS
===========================
Console Window Edit Keys:
^C -- user requests that everything stop
HOME -- go to the beginning of the current input line
^A -- ditto
END -- go to the end of the current input line
^E -- ditto
RightArrow -- move one position to the right in the current line
LeftArrow -- move one position to th eleft in the current line
^K -- delete the rest of the line
^W -- move the cursor to the next word in the current line
^Q -- move the cursor to the previous word in the current
line
UpArrow -- display the previous line from the command history
DownArrow -- display the next line from the command history
Backspace -- delete the previous character
Delete -- delete the current character
TAB (^I) -- 'tab completion': find the a file that matches the
word to the left of the cursor
Console handler bugs:
Sometimes control-C doesn't properly display the command prompt.