CYGWIN
lite
|
|
|
|
The Basics
 
bash is a user interface to a computer's operating system.
Most popular operating systems today use a graphical user interface (GUI)
like the Win95 Explorer or Mac Finder, but also include a command-line
interface (CLI) like the MS-DOS Prompt. bash is a member of the
breed of CLIs called shells that are the dominant form of user
interface in UNIX systems.
In 1983, the Free Software Foundation (FSF) began the
GNU (Gnu's Not Unix) project to implement a complete UNIX-like operating
system that would be covered by the innovative GNU General
Public Licence, or "copyleft," making it free to copy and modify.
The FSF intended not only to rewrite the hundreds of utilities that make up a
full UNIX implementation, but to improve upon them where possible.
The first widely used UNIX shell, called simply
sh, was written by Steve Bourne of AT&T Bell Labs and is known
as the Bourne Shell.
GNU bash, the "Bourne Again SHell," is the FSF improvement on
sh--the realization of a small part of that goal. Cygwin-Lite,
as well as much of the Cygwin environment, is also covered by the GNU GPL.
Command-line interfaces have both advantages and drawbacks. Some of the advantages are fast access to a large number of tools and the ability to perform tasks on many files at once (sometimes called "batch processing"). A major drawback, however, is that every command must be memorized by users and typed exactly. bash eases this shortcoming by TAB-completion, one of the Free Software Foundation's major usability improvements. You may type partial names of commands or files followed by a TAB and bash will automatically complete them if possible; if not, a second TAB will show a list of choices. No choices usually means that you misspelled something or forgot which directory you're in.
Here is a quick example to demonstrate. There will be examples throughout this tutorial; I recommend that you try them out for yourself to learn by doing. If you ever get stuck in an example, Ctrl-C (^C) will exit a program or Ctrl-D will end a file. Type w followed by two TABs, which will show a list of commands or files beginning with that letter. Now type c /eTAB/pTAB and ENTER. You should see something like this:
[05:03:00]~$ w wait wc.exe while [05:03:00]~$ wc /etc/profile 33 71 470 /etc/profile [05:03:00]~$ |
bash also supports extensive command-line editing features based on those found in GNU Emacs. bash keeps track of your command history; the Up cursor arrow or Ctrl-p will recall the last command, and the Down arrow or Ctrl-n will move back. You can search the history with Ctrl-R. A few movement keys are Ctrl-A to move to the beginning of the line, Ctrl-E to move to the end, and Ctrl-W to delete a word backwards. Other keys are listed in the READLINE section of the bash documentation (note that in Cygwin, the "Meta" or M- key is ALT).
Directory Structure and Mounts
When you start bash, you are automatically in your
home directory, something like /home/user/ , but which can
always be
abbreviated with a tilde as ~/. (Likewise, the present directory
can be referred to as ./, and its parent by ../.)
If you've used UNIX or Linux before,
you are probably familiar with the concept of a home directory
based on your user name. Cygwin determines your Windows login name by the
id utility. (This is why the title bar briefly says id
when you first start bash. It will always say the name of the last
program executed.) You can see your own user name and full path of your
home directory like this:
[05:03:00]~$ id -un user [05:03:00]~$ echo $HOME /home/user [05:03:00]~$ cygpath -w $HOME C:\cygwin\home\user [05:03:00]~$ |
Since Cygwin is a UNIX-like environment, it creates a UNIX directory tree in the C:\Cygwin directory. The MS-DOS directory tree is similar to UNIX, but it is different in several important ways. The one you might notice first is a slash (/) instead of a backslash (\) as the directory separator. In bash, the backslash is instead used as an escape character to prevent bash from interpreting special characters like $,~, space, or even newline (ENTER). As in MS-DOS, you may also use double quotes to represent directory or file names with spaces.
The more important difference between the UNIX and MS-DOS directory structures is the concept of a root directory. All MS-DOS directories are associated with a drive letter (A:\, C:\, D:\, etc.), while UNIX has a single directory referred to by / called slash or root. All filesystems--hard disk, floppy disk, CD-ROM, etc.--are mounted on /. This allows more flexibility than the MS-DOS structure. Here is an example of mounting some MS-DOS directories in cygwin. The commands mkdir (make directory) and ls (list) are something like MS-DOS md and dir; mount has no equivalent.
[05:03:00]~$ mkdir /c [05:03:00]~$ mount "C:" /c [05:03:00]~$ ls /c/*BAT /c/AUTOEXEC.BAT [05:03:00]~$ ls /c/Program\ Files/Accessories/ CIS.SCP HyperTerminal PPPMENU.SCP SLIP.SCP SLIPMENU.SCP WORDPAD.EXE [05:03:00]~$ mkdir /floppy [05:03:00]~$ mount "A:" /floppy [05:03:00]~$ mkdir /Desktop [05:03:00]~$ mount "$WINDIR/Desktop" /Desktop [05:03:00]~$ ls /Desktop All Your Base Are Belong to Us.swf CD Player.lnk Phone Numbers.TXT Winamp.lnk [05:03:00]~$ mkdir ~/docs [05:03:00]~$ mount "C:\My Documents" ~/docs [05:03:00]~$ mount Device Directory Type Flags C:\WINDOWS\Desktop /home/user/Desktop user textmode C:\My Documents /home/user/docs user textmode C:\cygwin\bin /usr/bin system textmode C:\cygwin\lib /usr/lib system textmode C:\cygwin / system textmode C: /c user textmode A: /a user textmode [05:03:00]~$ |
Moving Around
You probably don't want to do all of your work while in your home directory
(~/),
so it would be helpful to know how to move around. If you've experimented,
you've probably found that cd is the "change directory" command
in Cygwin as well as MS-DOS. bash cd can be used like the one in
MS-DOS; simply type cd followed by the path name of the directory
you want to go to. However, bash cd also has several other
features. cd by itself will return you to ~/. This might
get frustrating if you had typed a long path name to get somewhere and then
accidentally typed cd by itself--except that bash provides
cd -, a "go to last directory." If you ever become confused about
where you are, you can use pwd (present working directory) for a
full path name.
[05:03:00]~$ cd /usr/share/vim/syntax [05:03:00]/usr/share/vim/syntax$ cd [05:03:00]~$ pwd /home/user [05:03:00]~$ cd - /usr/share/vim/syntax [05:03:00]/usr/share/vim/syntax$ cd .. [05:03:00]/usr/share/vim$ ls syntax tutor [05:03:00]/usr/share/vim$ cd - /usr/share/vim/syntax [05:03:00]/usr/share/vim/syntax$ cd ../tutor [05:03:00]/usr/share/vim/tutor$ |
Moving and Removing Files
bash cannot move, copy, or remove files on its own; keeping with
the UNIX philosophy of dedicated tools that must be combined for bigger
tasks, this functionality is accomplished by the utilities
mv, cp, and rm. These and other executable files can be found
in the /bin directory. bash will expand
wildcard characters like ? (any one character) or
* (and number of any characters) as multiple arguments to these
utilities.
cp must always be followed by at least two file or directory name arguments. The final argument is the destination; to copy to the present directory, use ./ as the destination. cp can take as many arguments as you want. By default, directories are not copied, but they will be if you use cp -r (recursive for files) or cp -R (recursive for directories, copy entire tree). mv likewise takes two file or directory name arguments, but moves file(s) instead of copying. Unlike cp, mv moves directories by default. rm is like MS-DOS del, but there is no undelete or Recycle Bin. rm also has -r and -R options, making it the most dangerous command in Cygwin. Using rm in combination with rmdir is usually a better idea than using rm -r.
[05:03:00]~$ cp /etc/profile profile [05:03:00]~$ ls Desktop docs profile [05:03:00]~$ cp -r /etc ./ [05:03:00]~$ ls Desktop docs etc profile [05:03:00]~$ ls etc/ profile profile.d [05:03:00]~$ rm e*/p* rm: etc/profile.d: is a directory [05:03:00]~$ rmdir /etc/profile.d [05:03:00]~$ rmdir /etc [05:03:00]~$ ls Desktop docs profile [05:03:00]~$ rm rm: too few arguments Try `rm --help' for more information. [05:03:00]~$ rm --help Usage: rm [OPTION]... FILE... Remove (unlink) the FILE(s). -d, --directory unlink directory, even if non-empty (super-user only) -f, --force ignore nonexistent files, never prompt -i, --interactive prompt before any removal -r, -R, --recursive remove the contents of directories recursively -v, --verbose explain what is being done --help display this help and exit --version output version information and exit Report bugs to fileutils-bugs@gnu.ai.mit.edu [05:03:00]~$ |
Working with Standard Files and Redirection
The MS-DOS Prompt allows you to perform relatively simple tasks from the
command line and slightly more complicated tasks using batch files.
As you are probably beginning to realize, though,
bash, especially when combined with other command-line tools,
is a powerful environment that rivals some programming languages.
This functionality is based on simple text files.
While text files do not sound powerful, this section will explain how
to use them to accomplish many tasks.
One of the foundational principles of UNIX is that "everything is a file." In shells like bash your interaction is through three special files: Standard Output (STDOUT) for regular program output, Standard Error (STDERR) for program error output, and Standard Input (STDIN) for input. These files provide a very simple way to interface different tools. You can use the redirection operators |, <, >, 2>, &>, and >> to change the way bash would normally treat these files. We have already used piping with less; the | sends STDOUT from one program to STDIN of another. STDOUT is normally displayed to the screen; with the bash command help, this was too much for one screen. less, a pager (a program that displays text one page at a time), took this output as STDIN and produced just one page of its own STDOUT.
The other operators redirect to or from other files. < sends a file to STDIN, > sends STDOUT to a file, 2> sends STDERR (also called file descriptor 2) to a file, and &> sends both STDOUT and STDERR to the same file. Changing the > to a double >> in the output redirection commands causes the redirection to add to the end of the file instead of overwriting it. You can use this with the bash built-in echo to create your own file and then view it will cat (conCATenate file(s) to STDOUT).
[05:03:00]~$ echo "This is a file" > myfile [05:03:00]~$ cat myfile This is a file [05:03:00]~$ echo "This is the second line" >> myfile [05:03:00]~$ cat myfile This is a file This is the second line [05:03:00]~$ cp > myfile cp: missing file arguments Try `cp --help' for more information. [05:03:00]~$ cat myfile [05:03:00]~$ cp 2> myfile [05:03:00]~$ cat myfile cp: missing file arguments Try `cp --help' for more information. [05:03:00]~$ echo "This is a file" > myfile [05:03:00]~$ cat myfile This is a file [05:03:00]~$ |
Redirecting STDOUT or STDERR is more useful with utilities that send
output to both, such as grep (the General Regular Expression Parser).
grep searches through files using regular expressions
(patterns matching characters), and, like the file utilities, takes at least
two arguments. The first argument is the pattern to search for, followed by at
least one file to search through. Often you would like to search through every
file in a directory, and so you issue a command like grep "This" *.
grep can only search files, not directories, but "*" matches both.
When grep finds a match, it outputs the name of file and matching
line, but also sends output to STDERR when it comes to a directory. It is
often helpful to separate STDOUT and STDERR in these cases.
[05:03:00]~$ grep "This" * grep: Desktop: Is a directory grep: docs: Is a directory grep: etc: Is a directory myfile:This is a file [05:03:00]~$ grep "This" * > grep_STDOUT grep: Desktop: Is a directory grep: docs: Is a directory grep: etc: Is a directory [05:03:00]~$ grep "This" * 2> grep_STDERR grep_STDOUT:myfile:This is a file myfile:This is a file [05:03:00]~$ cat grep_STDERR grep: Desktop: Is a directory grep: docs: Is a directory grep: etc: Is a directory [05:03:00]~$ |
Subshells and Job Control
Occasionally you might want to use the output of one program as only
part of the input to another program, such as copying all files that
grep matches into a directory. If you try using a pipe,
cp will complain that the last argument is not a directory, but
piping doesn't allow you to add an extra argument at the end. You can
redirect the output of one command to a file and then turn that file
into a shell script, but that requires extra typing
and creates messy temporary files.
The solution to this problem is treating bash itself as a utility using a subshell. The idea of a subshell is related to the concept of STDOUT. Just as you can run multiple copies of bash at the same time in different windows or consoles, each with its own STDOUT, STDERR, and STDIN, you can run a second copy of bash from within another bash session. Commands for the subshell are enclosed with the syntax $(commands). There is an older subshell representation that surrounds subshell commands with backquotes (e.g., `commands`), but since that appears confusingly similar to single quotes in shell scripts the $(...) syntax is preferred.
Subshell STDOUT is taken as STDIN to your current shell, while subshell STDERR is added to the STDERR of your shell. This means that subshell output must be either commands or arguments to commands. Therefore, to copy all files matching a certain pattern the subshell output should be a list of file names, which can be used as arguments to cp; GNU grep provides a -l option that lists only files names.
[05:03:00]~$ mkdir mydir [05:03:00]~$ cp $(grep "This" *) mydir/ grep: Desktop: Is a directory grep: docs: Is a directory grep: etc: Is a directory grep: mydir: Is a directory [05:03:00]~$ ls mydir/ grep_STDOUT myfile [05:03:00]~$ |
In the last example, if grep had been searching through and then cp had been copying hundreds of large files it could have taken quite some time to finish. You could start another shell, or just wait, but bash also offers a form of multitasking called job control. When you start a program, it will normally take control from bash. This is fine for short programs that complete quickly or for interactive programs that require input, but not for possibly time-consuming tasks like searching files. bash allows you to put these jobs in the background. The easiest way to do this is to put an & at the end of the command (e.g. cp ~/largefiles/* ~/newdir/ &). bash outputs a job number followed by a process ID. For now, you can ignore the process ID (the difference is that bash assigns job numbers, while the operating system assigns process IDs).
Unlike subshells, background jobs run in the same copy of bash while you perform other tasks. Whenever a backgroud job completes, bash will output a notice with the job number, exit status, and command. Though the job is in the background, it still shares STDOUT and STDERR; you may want to redirect the output to a log file. If you accidentally forget to redirect output, Ctrl-C won't work; you can end a background job with the bash built-in kill followed by the job number with a percent sign (e.g., kill %1). Since STDIN is a different file from STDOUT, this will work even if the job is filling the screen with output and you can't see what you're typing.
A good candidate for this is the find command, which searches a directory tree by criteria and outputs the names of files that match. For example, find /c -name "*" will output the names of all the files on the C: drive, or find ~/ -mtime -1 will output all files in your home directory that have been modified in the last 1 day. find is a good command to run in the background, but if the output is not saved to a file it can quickly fill the screen. Try find /c -name "*" &, then end it with kill %1. Here is an example of logging the output to a file:
[05:03:00]~$ find /c -name "*" >findlog & [1] 1019475 [05:03:00]~$ [1]+ Done find /c -name "*" > findlog & [05:03:00]~$ |
There is also job control for interactive programs that take typed input such as an editing program or a less session. Instead of being put in the background, which would make little sense for a program that expects interaction, these jobs can be suspended with Ctrl-Z (^Z). bash will output a message with the job number, the message Stopped, and the command. You can put stopped jobs in the background with bg, but be careful doing this with interactive programs; they may not behave as you expect.
You can come back to a background or stopped job by bringing it to the foreground with fg. However, stopped jobs take precedence over background ones, so fg will bring the most recently used stopped job if there are both background and stopped jobs. The jobs built-in command will show all active jobs. The most recent job is marked with a + next to its job number, and the job previous to that with a -. fg %- brings the second most recently used job to the foreground. You may also pick a specific job to bring to the foreground with fg followed by a percent sign and the job number (e.g., fg %3).
Here is a somewhat unlikely scenario to demonstrate. vimtutor is an interactive guide to the vim text editor, and the -exec option to find executes a command on found files ({} represents the file name, and /; ends the -exec command).
[05:03:00]~$ vimtutor [1]+ Stopped vimtutor [05:03:00]~$ find /c -name "*" &>findlog & [3] 937861 [05:03:00]~$ find /c -name "*" -exec grep "qz" {} \; &>greplog & [2] 948965 [05:03:00]~$ jobs [1]+ Stopped vimtutor [2] Running find /c -name "*" >&findlog & [3]- Running find /c -name "*" -exec grep "qz" {} \; >&greplog & [05:03:00]~$ fg [2] Exit 1 find /c -name "*" >&findlog & [3]- Done find /c -name "*" -exec grep "qz" {} \; >&greplog & [05:03:00]~$ |
An Introduction to Shell Scripting
The UNIX philosophy of interfacing several tools to accomplish a task
can be annoying when you find yourself typing complicated commands several
times. Shell scripts, which are like MS-DOS batch files
but far more powerful, provide the answer to this problem. The scripting
capabilities of the Bourne shell are one of the main reasons for its
popularity; bash expands on sh while remaining compatible.
In many cases, shell scripts act exactly like executable programs, or, more
accurately, make the shell behave as if it were a different executable
program. For example, the vimtutor program is really a shell
script that copies the tutor text file to a temporary location and
then starts vim.
Say you often want to use grep recursively as in the above example. First we need to assign any changing parameters involved to variables. The parameters to grep and find above are the search string and directory, which will be command-line arguments to the script. As in MS-DOS batch files, variables given from the command line as arguments are referred to by numbers; all variables in bash are marked with a $ (dollar sign), so the script name is $0, the first argument is $1, the second $2, etc. We can position these parameters so that the script acts just like normal grep: the search string followed by what to search. We can now build a short shell script. With echo, single-quotes are necessary to correctly print double quotation marks. With the -type f argument, find will report only files, not directories. See TESTS in the find documentation for more details.
[05:03:00]~$ echo 'find $2 -name "*" -type f -exec grep $1 {} \;' > grepr [05:03:00]~$ cat grepr find $2 -name "*" -type f -exec grep $1 {} \; [05:03:00]~$ ./grepr "This" ~/ /home/user/myfile:This is a file /home/user/grep_STDOUT:myfile:This is a file [05:03:00]~$ |
Like subshells, shell scripts are run separate from your interactive bash session. However, you can choose to use a program other than bash with a special comment of the form #!/bin/sh on the first line of the shell script. /bin/sh can be replaced with the path to any script interpreter (like /bin/bash) if needed. Comments are marked with # (pound sign) in bash; it will ignore any commands that come after a #. You can type comments to yourself at any time in bash, like ls #listing files now, but they are most useful in clarifying shell scripts.
Why would you want to use a different program to run a shell script? In some cases, the script is written in a language bash cannot understand (like perl), but more often it is for portability and efficiency. Virtually every UNIX system has a shell named sh that is compatible with the Bourne shell. (The Cygwin sh is ash, which is a good low-memory shell.) If you write shell scripts using #!/bin/sh, that script will run on UNIX systems like IBM AIX, Sun Solaris, or Compaq Tru64 that may or may not have bash installed. More pragmatically, sh is a smaller program (especially since it does not have interactive features like TAB-completion or command-line editing) and so takes less memory and will run faster. On the other hand, bash has many shell scripting features that sh does not.
So, while grepr is a useful short script, there are several problems with it. It does not specify a command interpreter, nor does it give usage information, so if you don't use it very often you may forget what it does. While comments would probably clarify the commands in the script, it would be better if grepr would tell you how to use it, just as grep does. This can be done with a compound command (a command that usually take more than one line), the if statement. From this point on, you will need to write your shell script with a text editor; it is possible to use MS-DOS EDIT.COM, but the included vim editor has many more features and, although difficult at first, is worth learning to use. vim is "Vi IMproved"; like sh, a version of vi is found on virtually every UNIX; if you ever need to work on an unfamiliar UNIX, you can rely on vi as a text editor. Run vimtutor for an introduction.
Usually the easiest way to find out how to use a command is to type its name with no arguments, as grep does. We can use the if statement with the $# variable, which reports the number of arguments, to check if no arguments were supplied. if statements begin with a test condition; we want to know if the number of arguments is less than one. The bash built-in test, which can be written as [ ] for readability, supplies the comparison -lt for "less than." [ ] is followed by a semicolon and the control word then. If the test condition is true, the commands following then will be executed; if not, bash will resume execution after the control word fi (if backwards). The command we want to add will output usage information. Here is the script as it should be typed in your text editor (note that test is picky about spaces) and some comments, followed by a comparison with the behavior of the real grep:
#!/bin/sh # greps files recursively through a directory tree if [ $# -lt 1 ]; then #check if user provided echo "Usage: $0 PATTERN [DIRECTORY]" # enough arguments, otherwise fi # print usage find $2 -name "*" -type f | xargs grep $1
[05:03:00]~$ ./grepr Usage: ./grepr PATTERN [DIRECTORY] [05:03:00]~$ grep Usage: grep [OPTION]... PATTERN [FILE]... Try `grep --help' for more information. [05:03:00]~$ |
Occasionally you may find that a shell script needs to use the same few commands several times. You could place these commands in a separate script, but bash provides functions to simplify scripts. Functions begin with the word function followed by a name and an opening brace ({). After the commands, a line with a closing brace (}) ends the function. Functions, like shell scripts, are a named list of commands, but are executed in the same shell, not a separate one. bash accomplishes this by "memorizing" the function (putting it in memory), but not executing it until the function is called by name.
This improves one of the most interesting and confusing uses of shell scripts: recursion (a script executing a copy of itself). Normally, recursion with shell scripts is extremely inefficient since a new shell is required for each copy of the script. With functions, however, the lines of the function are simply copied within the shell. As an example, consider the following script, which imitates the basic find. The for compound statement will set a variable to each item in a list successively (you do not use $ with variable names when defining them); * expands to a list of all the files in one directory. for does not give a path name or recurse, but the $PWD variable (present working directory) provides the path, and we can use an if in a function to recurse if the file is a directory. At the end, showfiles cleans up after itself by removing the no longer needed variable i with unset.
#!/bin/bash function showfiles { for i in *; do if [ -e $i ]; then #test if any files exist (empty directories) echo $PWD/$i fi if [ -d $i ]; then #test for directory, call self if true cd $i showfiles cd .. fi done unset i } showfilesNote the recursive call right after changing directories in the second if. Also, the function is defined, but not executed until the last line, which is simply showfiles, a call to the function. You can probably imagine a few basic improvements to this script, such as allowing an argument for where to start searching; experiment with adding more functionality.
Defining a function is analogous to writing a shell script such as grepr, while actually calling it is like typing the command. Like shell scripts, functions can also take arguments. If you're wondering if there is a way to access functions from the bash prompt like in a shell script, there is: the source command. source is a bash built-in command that copies lines from a file exactly and executes them one at a time, just as if they had been typed by the user. You can create a file that defines one or more functions but never calls them, like showfiles above would be without the last line, and then put the functions in bash's memory with the command source function_file, where they are available from the command line and completed with TAB-completion. Sourcing files is so common that its abbreviation is simply . (dot), so assuming you put the showfiles function definition (without the call on the last line) in a file named showfiles you can have bash memorize it with the command . ./showfiles.
The bash environment
It was briefly mentioned in an earlier section that bash sets
environment variables like $HOME, which is used to determine your
home directory, automatically. $PWD, used in the function example
above, is another of bash's environment variables, which
by convention are written with all capital letters. bash uses these
variables in various commands. For example, recall from the
Moving Around section that cd without arguments
will take you to your home directory, while cd - will return you
to the directory you were in previously. These commands actually change the
directory to the values in $HOME and $OLDPWD respectively.
You can set the value with a command of the form OLDPWD=/path
(remember not to use the $ when setting variable values):
[05:03:00]~$ cd /etc [05:03:00]/etc$ cd [05:03:00]~$ echo $OLDPWD /etc [05:03:00]~$ OLDPWD=/usr/share/vim [05:03:00]~$ cd - /usr/share/vim [05:03:00]~$ echo $OLDPWD /home/user [05:03:00]/usr/share/vim$ cd [05:03:00]~$ |
It's best to not change system-defined variables like $USER or $HOME unless there is some problem with your user name (for example, spaces in a user name can be confusing and difficult to type), but other bash environment variables are customizable. To see the names of all environment variables, you can type echo $ followed by two tabs, which will list all defined variables. One of the most important of these is $PATH which is a colon-separated list of directories that bash searches for commands. As mentioned earlier, the current directory is not in the path, so you need to type ./ to execute a files there.
You can redefine $PATH to include your home directory with a command like PATH=$PATH:$HOME, but since variables are stored internally, the redefined variable will only last until you exit bash. So how does bash set variables like $PATH, $HOME, or $USER in the first place? The secret is in the bash system initialization file, /etc/profile. Every time bash starts with the --login option or from a login prompt, it automatically sources the commands in this file. /etc/profile contains lines like PATH="/usr/local/bin:/usr/bin:/bin:$PATH", USER="`id -un`", andHOME="/home/$USER". Notice that the file is written with old-style `id -un` instead of $(id -un).
You may have also noticed a line like export HOME USER in /etc/profile. The built-in command export makes a variable available to subshells. The idea behind export is that not all variables are important, and so only important ones need to be given to subshells or shell scripts. You can see all current exports by typing export with no arguments; some of those in Cygwin ($COMSPEC, $WINDIR) are left over from the Windows environment files and so follow the MS-DOS path naming convention but are listed with a double backslash in bash.
Since bash is designed for multi-user systems, each user has a personal initialization file that is sourced like /etc/profile is for the whole system, ~/.bash_profile. Additionally, there is a startup file ~/.bashrc that is sourced for all interactive shells. This allows you to put a command that you only want to see the first time you start bash, such as echo "Welcome, $USER" in .bash_profile. These configuration files are hidden files in your home directory. In UNIX, hidden files are simply ones that begin with a . (dot), which are only shown by commands such as ls when the -a (all) option is used. Hidden configuration files are sometimes called rc files since they often end with the letters rc ("run commands").
To see how the sourcing works, you can put lines that echo information, like echo "This is $HOME/.bash_profile" in ~/.bash_profile. When you start bash, you would see something like this:
This is /etc/profile This is /home/user/.bashrc This is /home/user/.bash_profile This is /home/user/.bashrc [05:03:00]~$ |
Several of the customizations previously mentioned would be good to put in your .bashrc. If you write several shell scripts, you could create a ~/bin directory and add it to your path with the line PATH=$PATH:$HOME/bin (make sure to include the old path, or bash will complain that it can't find commands like ls, which are in the /bin directory). You can also define useful functions or source files with functions in them.
Another fun to customize environment variable is the prompt bash outputs when it is ready to read a command. You may have noticed that /etc/profile exports a variable called PS1, which is "prompt string 1," the default prompt. In Cygwin-Lite, PS1 is something like [05:03:00]~/$ , the current time followed by the present working directory and a $. Besides regular characters, you can use several special escaped characters bash provides to build your own PS1. A few of these are \t (the current time), \w (the present working directory), \u (user), \! (how many commands are in your history), and \[...\] for control sequences like changing colors; others are listed in the bash documentation under PROMPTING. A prompt like [05:03:00]~/$ would be set as PS1="[\t]\w\$ ".
Aliases are another type of environment customization besides variables and functions to put in .bashrc. An alias is a word that you want bash to replace when it is entered as a command. You can create an alias with a command like alias md='mkdir'. Now, if you type md newdir, bash will translate it to mkdir newdir before executing it. Aliases are best put in .bashrc since they are never exported. If there is more than one possible source for a command, for example an alias and function with the same name, bash's preference goes in this order: alias, function, built-in, then program like a shell script or executable.
Another rc file that effects bash is .inputrc,
which controls the READLINE command-line editing features that bash
and other programs use. You can use .inputrc to customize
command-line editing. Say two aspects of
bash's command-line editing bother you: the bell sound every time
you use TAB-completion, and the lack of a keyboard shortcut to exit like most
graphical application have. You can create a file in ~/ called
.inputrc and add the following lines:
set bell-style none
"\M-q": "exit\n"
The first turns off the bell, and the second binds ALT-q (remember ALT is
the META key in Cygwin) to exit followed by a newline (\n),
which is what you type to quit. You can bind any text in this way, but
keep in mind that you may be overwriting a default value. (You can see all
bound keys in the .inputrc format with the bind -p
command, which bind -P outputs in a slightly more
readable way.)
This guide covers only the basics of using and customizing bash. The best place to find more information or help is on the Internet; here are a few places to start.