Cross Platform Ch Shell Programming
  1. Ch Shell (ch) is a C compatible and genuine C shell
  2. Ch Shell versus C Shell, Bash and Korn Shell
  3. Keyboard shortcuts in Ch shell
  4. Ch Extensions to C for Shell Programming and Scripting
  5. Ch Shell difference between Windows and Unix
  6. More examples

Ch Shell (ch) is a C language shell and genuine C shell

Shell programming with scripts is effective to automate repetitive tasks such as system administration, regression test, and rapid prototyping. The language syntax of conventional Windows MS-DOS and Unix shells such as Bourne shell, C shell, and Korn shell are awkward. Similar to symbolic mnemonic forms of lower level assembly languages, special meanings for clusters of metacharacters in MS-DOS/Unix shells are difficult to remember. Therefore, large shell scripts written in these MS-DOS/Unix shell programming languages are hard to read and difficult to change and maintain. In addition, the power for these MS-DOS/Unix shell programming languages is limited. Like millions of hard-to-program VCRs blinking 12:00 in American living rooms, only a fraction of the capabilities of these shell programming languages are used by the majority of MS-DOS/Unix users. Most users treat these MS-DOS/Unix shells as command interpreters; their day-to-day programming tasks are handled in C or other conventional programming languages.


"I'm starting to use Ch for scripting and to learn C. I often have to write little scripts and learn more and more of Bash, GNU tools, and Linux to get done what I wasn't. I then thought I wish there was a shell in C, not like the other shells that are strangely called C shells, csh or tcsh, which are not like C.

Even though learning C is much harder than Bash or some other scripting language, I realized learning C would have a lot of advantages. A lot, if not most, of open source and other software is written in C and understanding C would unlock all that. Also if I was careful I could write stuff cross platform that would work on Linux and Windows. Now whenever I have to script something I try to do it in C and/or Ch. Ch is a great product. I can do my scripting and learn C at the same time."
-- James Richards

"I appreciate ch and SoftIntegration. I have used ch as a unix shell in the past. Right now I use it in the Linux classes that I teach as an alternative to the standard shells. I also use it for myself to brush up on my C/C++ basics or to knock off a quick prototype for my personal use.

Keep up the great work, guys. I believe that this is a fine product."
--Robert Ritter, Technical Instructor, Centriq Training

Read More Testimonials

Ch is an interpretive implementation of C as Unix/MS-DOS shell. ch can also be used as a login shell the same as Unix shells. Ch bridges the gap between the C language and Unix/MS-DOS shell. Unix shell commands, such as vi, ls, mv, grep, find, awk, and sed can run in Ch in both Windows and Unix, they are integrated into Ch script command. It is designed for both interactive command interpretation and shell programming. Ch is a true VHLL for programming while it retains the shell features such as command-line editing, tab completion, history, aliases, piping, wildcarding, iteration etc. When Ch is used in a single command mode, most features of Ch are the same as conventional Unix shells such as Bourne shell, C shell, and Korn shell, and MS-DOS shell in Windows. However, since Ch is a superset of C, shell scripts written in C and extended Ch shell programming features are much more powerful, efficient and easy to maintain.

Getting Help

man unix_command Read the manual on a unix_command. i.e: 'man ls' to see the manual on "ls"
man C_function_name Read the manual on C_function_name. i.e: 'man strcpy' to see the manual on C function 'strcpy'

Home directory and wildcards

~ Your home directory
~username Home directory of username
~/subdirectory The subdirectory directory in your home directory
cd - it goes back to your previous directory from your current working directory.i.e: if you are in c:/windows, go to C:/Program Files/Microsoft, type 'cd -' to go back to c:/windows.
cd -- it switches you to the previous previous directory. i.e, if you are in /usr, go to /usr/local, then go to /usr/local/bin, type 'cd --' to go back to /usr.
cd ~ or cd It goes to your home directory from your current working directory
* Any number of characters. i.e: 'ls *.ch' will list all files ending in .ch
? Any single character

History to show the previous commands executed

!! Re-execute the last command (or use the arrow shortcut described below)
!number Execute a command by number
!string Execute the last command beginning with string
^old^new Execute the last command, substituting old with new
ctrl-p Scroll backwards through previous commands

Pipes and output redirect

command > filename Redirect command's standard output to overwrite file 'filename'.
command >> filename Redirect command's standard output to append to the file 'filename'
ch -r command >filename (in both Windows and Unix)
command >filename 2>&1 (in Unix)
command 1>filename 2>&1 (in Windows)
Redirect command's standard output (stdout) and standard error (stderr) to the file 'filename'
command < filename Redirect command's standard input to read from the file 'filename'
command1 | command2 Redirect command1's standard output to command2's standard input
command & Run command in background

Ch Shell versus C Shell, Bash and Korn Shell

In terms of shell programming, Ch will be as close to C shell as possible, but no closer. Ch shell is a genuine 'C' shell and portable in Windows and Unix while C Shell (csh) has nothing like more like C comparing with other languages such as php etc except its name. The semantics of history and alias features in Ch are similar to C-shell. But the syntax is different from C-shell because Ch is a superset of C. The following table highlights the syntax differences between Ch shell and C shell, but with the same semantics.

C Shell Ch Shell
$#argv _argc
$argv[*] strjoin(" ", _argv[1], _argv[2], ..., _argv[_argc])
$argv strjoin(" ", _argv[1], _argv[2], ..., _argv[_argc])
$* strjoin(" ", _argv[1], _argv[2], ..., _argv[_argc])
$argv[1-n] strjoin(" ", _argv[1], _argv[2], ..., _argv[n])
$0 _argv[0]
$argv[n] _argv[n]
$1 $2 ... $9 _argv[1] _argv[2] ... _argv[9]
$argv[$#argv] _argv[_argc]
set prompt = "ch> " _prompt = "ch> "
set path = (/usr/bin /bin) _path = "/usr/bin /bin"
umask 022 umask(022)
setenv PATH "/usr/bin /bin" putenv("PATH=/usr/bin /bin")
echo $PATH printf("%s\n", getenv("PATH"))
echo $PATH echo $(getenv("PATH"))
echo $PATH echo $PATH
echo ${PATH} echo ${PATH}
echo $path printf("%s\n", _path)
echo $path echo $_path
unsetenv PATH remenv("PATH")
printenv PATH getenv("PATH")
unset path remvar _path
unset path #pragma remvar(_path)
unset i remvar i
unset i #pragma remvar(i)
set i =90 int i = 90
set i =91 i = 91
set hostnam =`hostname` string_t hostnam =`hostname`
set host =`hostname` _host =`hostname`
alias rm "rm -i" alias("rm", "rm -i")
alias rm alias rm
alias rm alias("rm")
alias alias
alias alias()
unalias rm unalias rm
unalias rm alias("rm", NULL)
alias f "find . -name \!:1 -print" alias("f", "find . -name _argv[1] -print")
alias e "echo \!* \!$ \!#" alias("e", "echo _argv[*] _argv[$] _argv[#]")
eval ls streval("`ls`")
eval ls system("ls")
eval setenv NAME VALUE streval("putenv(\"NAME=VALUE\")")
/usr/bin/ls * /usr/bin/ls *
./cmd -option ./cmd -option
status _status
ls ~ * ls ~ *
ls > output ls > output
ls | tar -cf tarfile ls | tar -cf tarfile
ls $PATH ls $(getenv("PATH"))
ls $PATH ls $PATH
ls $path ls $_path
history = 100 _histsize = 100
history history
$cmd $cmd
!l !l
!l -agl !l -agl
!3 13
!-1 !-1
!! !!
vi `grep -l "str1 str2" *.c` vi `grep -l "str1 str2" *.c`
/* use $ inside ` ` */
set filename="test.txt"
set tmpFilename=$filename
echo `wc -w $tmpFilename`
string_t filename = "test.txt";
string_t tmpFilename = filename;
echo `wc -w $tmpFilename`;
.cshrc .login .logout .chrc .chlogin .chlogout (in Unix),_chrc (in Windows)
.cshrc .login .logout .chsrc .chslogin .chslogout (in Unix), _chsrc (in Windows)

Bash and Korn Shell Ch Shell
eval $(date "+month='%B' mon='%m' year='%Y'")
echo $month $mon $year
string_t month, mon, year;
streval(`date '+month="%B", mon="%m", year="%Y"'`);
echo $month $mon $year
ls /non_exist_directory >junk 2>&1 ls /non_exist_directory >junk 2>&1
export PS1="\u@\H \W \A >" _prompt=stradd(_user, "@", _host, " ", _cwdn, " ",`date +%k:%M`, " >")

Prompt Description bash Prompt ch Prompt
Current Working directory \w _cwd
the basename of the current working directory \W _cwdn
User name \u _user
Full hostname \H _host
Hostname up to the first '.' \h `hostname -s`
The current history number \! _histnum
Time of day in 24-hour hh:mm \A `date +%k:%M`

Keyboard shortcuts in Ch shell

Copy and Paste (Two ways to do it):
  • Using Console GUI: if you want to copy and paste from GUI, you can run "console" from ch shell. it allows you to do copy and paste by clicking the button from GUI.
  • shortcut using mouse (this solution works in console GUI above and Ch shell):
    To Highlight the text you wish to copy: Click down once, with your cursor on one side of the text you want to copy, with your left mouse button. Hold the mouse button down. Then drag your mouse pointer over the text until all of the text you wish to copy is colored differently than the rest of the text on the page. Now let go of the mouse button. If you have highlighted correctly, the text should stay colored differently.
    To Copy: Right click the mouse.
    To Paste: Place your cursor where you want to paste, right click again to paste.
TAB: Autocomplete the filename, command or directory name from the cursor position.
Trick to handle a space in the filename or directory when having multiple options, add an escape '\' before the space ' ', then type 'TAB'. i.e:
   C:/> cd c:/do[TAB]
   Documents/               Documents and Settings/
   C:/> cd c:/Documents\ [TAB]
   C:/> cd "c:/Documents and Settings"/

Advantage in Ch shell running "cd [tab]" in ch shell will display a list of directories to select from, while other shells such as bash (version 4.1.2) will display a list of files (which are not necessary) and directories.
Ctrl+a: (home) moves the cursor to the line start (equivalent to the key Home).
Ctrl+e : (end) moves the cursor to the line end (equivalent to the key End).
Ctrl+p: (previous) recalls the prior command (equivalent to the key Up).
Ctrl+n: (next) recalls the next command (equivalent to the key Down)
Ctrl+u : clears the line content before the cursor and copies it into the clipboard.
Ctrl+k : clears the line content after the cursor and copies it into the clipboard.
Ctrl+w : clears the word before the cursor and copies it into the clipboard.
Ctrl+y : (yank) adds the clipboard content from the cursor position.
Ctrl+d : sends an EOF marker, which closes the current shell (equivalent to the command exit) if there is no text on the current line.
Ctrl+c : sends the signal SIGINT to the current task, which aborts and closes it.
Ctrl+z (available in unix only): sends the signal SIGTSTP to the current task, which suspends it. To execute it in background one can enter bg. To bring it back from background, the foreground command fg ('process name or id') can be issued.

Ch Extensions to C for Shell Programming and Scripting


"I am using Ch shell programming capabilities to automate the download and extraction of data from archive (*.ar) files using the Unix ar command for an automation system running under Win2000. I use ar within a Ch built-in 'for each' loop to extract all files (*.ar) within a given directory. It works beautifully.

I am very impressed with the capabilities of the Ch language, and plan to make more use of it in future in developing automation scripts."

-- Jeremy Walsh, National Institute of Water and Atmospheric Research, New Zealand


"I just stumbled on your product while looking for something else on the Internet. I had never heard of Ch prior to that, but so far I'm very impressed with everything it is capable of. I've been a C programmer for a long time and do mostly systems programming in an IT environment. I really like the Ch shell and the ability to run C code as a script. I can see a lot of uses for this in a systems programming environment. Just surprised I've never heard of it before now. Looks like you focus on larger companies and education. I haven't been in college in a long time and I've spent most of my career in small companies, but I do see its usefulness. I will definitely be exploring this further."

-- Robert Berry

"We use Ch for the classes 'Introduction to Computer Concepts' and 'General Applications Programming' to introduce the concept of interpreted/scripting languages and do a brief overview of shell commands. These are classes for non-computer science majors. Ch is ideal for our purposes; the conventional way (remoting to Linux servers) seems to be less effective for non computer science major students. Ch works great! Thank you very much."

--Yuliya Kopylova, University of South Carolina

"As a C debugger and learning tool -- being able to execute C snippets as scripts is a much better debugging method than breakpoints (at least for what I do). Plus if I run across a function I'm not familiar with I can just try it without the whole write/compile/link/run tedium. I especially love that I have access to the C interpreter, the WSH, and the Win32API. This way I can use regular C, VBScript, JScript, or MFC C++ seamlessly as the situation requires.

In summary: cool shell, very stable and reliable so far. Glad to see C holding the line against the barbaric Basic and Java incursions."

-- Weldon Goree, Sr. Network Administratorar

Read More Testimonials

Ch extends C with following features, which make it especially suitable for shell programming and cross platform scripting.
  • Ch can be used in either command shell or program mode interpretively.
    Ch language environment can be used as a command shell. In command shell, history substitution, event designator, quick substitution, command substitution, aliases, and file or directory name completion using a tab key are available in Ch. An example of Ch shell in action is given as follows:
       > hello.c
       Hello, world!
       (execute the famous hello.c program without compilation)
       > int i, *p;
       > p = &i; 
       > *p = 90;
       > printf("i = %d\n", i);
       i = 90
       >if (i == 90) printf("good\n"); else printf("bad\n");
       good
       > int **p2
       > p2 = &p
       > printf("**p2 = %d\n", **p2)
       **p2 = 90
       > ls * > junkfile
       (all file names go to junkfile)
       > i**p
       8100
       > array int a[2][3]
       > a = (array int [2][3])5
       > a
       5 5 5 
       5 5 5
       > 2*transpose(a)
       10 10 
       10 10 
       10 10 
       > which ls
       ls is aliased to ls -F  // if ls is an alias set in ~/[_]chrc
       >
       > int i;
       > for (i=0; i<6;i++) printf("%d\n",i);
        0
        1
        2
        3
        4
        5
       >
    

  • A quick calculator
     #return to get the calculation result from ch shell
     > 5*9-4+334-(5*9)*2
       285
     >
    

  • POSIX
    Ch supports POSIX for across platform directory and file processing. Sample code can be found here.

  • String data type
    C is a small language; it has no string data type. Pointers to char are handled as strings in C. Ch provides an alternative string data type for pointers. It eliminates potential bugs before they happen. The string data type can also be used with existing C functions and C data type of 'pointers to char'. For shell programming, a string data type is added to C in Ch. It is seamlessly merged with pointer to char. All functions defined in the standard C library header string.h are valid for both pointers to char and strings. String is a first-class object in Ch. For example, the following code fragment
          string_t s, a[3];
          s = "great string"
          s = stradd("greater ", s)
          strcpy(a[0], s);
          printf("a[0] = %s\n", a[0]);
    
    will display greater great string.

  • Foreach-loop is added for shell iteration.
    The code below will create three directories dir1, dir2 and dir3 in the current directory.
        string_t token, str="dir1 dir2 dir3";
        foreach(token; str) {
           mkdir $token;
        }
    
  • Here document and Verbatim output. The Here document and verbatim output features can be achieved using the code block feature of function fprintf. The Ch function sendApplet() below generates a C program. void sendApplet(char *x, char *y, char *expr) { fprintf(stdout, "#include<stdio.h>\n"); fprintf(stdout, "int main() {\n"); fprintf(stdout, " double x = %s;\n", x); fprintf(stdout, " double y = %s;\n", y); fprintf(stdout, " printf(\"x = %%f, \", x);\n"); fprintf(stdout, " printf(\"y = %%f \\n\", y);\n"); fprintf(stdout, " printf(\"%s = %%f\\n\", %s);\n", expr, expr); fprintf(stdout, "}\n"); } The above function sendApplet() can be rewritten in Ch as follows. If you want to redirect to a file instead of 'stdout', you can simple open a file and replace 'stdout' below with your file handler. void sendApplet(char *x, char *y, char *expr) { fprintf stdout << ENDFILE #include<stdio.h> int main() { double x = $x; double y = $y; printf("x = %f", x); printf("y = %f\n", y); printf("$expr = %f\n", $expr); } ENDFILE }

  • The controlling variable of the switch and case statement can be a string in addition to integral type. #!/bin/ch char *ch="SoftIntegration Ch"; float version=2; string_t hostname=`hostname`; switch (hostname) { case "mymachine": printf("Hello world\n"); break; case "testmachine": fprintf stdout << ENDPRINT Welcome to use $ch version $version SoftIntegration, Inc. ENDPRINT echo Ch is cool! I can now use a C program to backup files dump 0ubdsf 80 50000 50000 /dev/nrst0 /dev/sd0a break; default: break; }

    If you want to prevent the variable or expression substitution for '$', you can precede the '$' with '\'. '$' is passed unchanged if followed by a blank, tab, or end-of-line.

  • Variable substitution and command substitution with combination of shell commands and C code
    Shell commands such as sed, awk, wc, grep, etc. can be combined with C code to run in Ch with variable substitution and command substitution. Executable programs can also be used directly in a Ch script. Below is an example: #!/bin/ch string_t result1; char result2[50]; grep "test" myfile.txt; if ( _status == 0 ) { printf(" 'test' is found in myfile.txt\n"); } else { printf("Cannot find 'test' in myfile.txt\n"); } result1=`wc -l /etc/passwd`; echo $result1; strcpy(result2, `wc -l /etc/passwd`); printf("%s\n", result2); The output for result1 and result2 are the same in the above program.

  • Safe Ch is designed for the growing need of internet computing.
    In addition to restrictions imposed by conventional restricted shell, many other features are disabled in safe Ch for across-network internet computing. A system administrator may grant limited access to users using safe Ch.

  • System variables _argc and _argv for command line argument interface.
    System variables _argc and _argv are equivalent to arguments argc and argv in startup C function
        int main(int argc, char *argv[]);
    
    Assume program cpfile.ch contains the following statements.
        #!/bin/ch
        cp /dir/source/$(_argv[1]) /dir/dest/
    
    Program cpfile.ch can be used to copy any file located at directory /dir/source to directory /dir/dest. For example, the following commands
        > cpfile file1
        > cpfile file2
    
    will copy files file1 and file2 from directory /dir/source to directory /dir/dest.

  • FAQ
Ch Shell difference between Windows and Unix

Ch shell runs slightly different in Windows and Unix.

  • command substitution
    In windows ch shell, the following command substitution is supported.
       > `date`
       > char *a=`date`; 
       > echo $a
         Wed Nov 26 21:12:23 Pacific Standard Time 2011
    
    However, Ch shell in Windows doesn't support the following command substituion.
       > echo `date`
    
    In Unix Ch shell, they are all supported.

  • background process
    In windows, Ch shell supports background process ( & ) for win32 GUI applications, not the unix utilities. For example: "ls & " doens't work. however, "notepad &" works fine. In Unix, there is no such a problem in Ch shell.

  • stdout and stderr redirect
     > ch -r command >filename  (in both Windows and Unix)  
     > command >filename 2>&1   (in Unix)  
     > command 1>filename 2>&1   (in Windows)
    
  • path
    In Unix, ch shell works the same as bash or csh. The working directory in Ch shell in windows differs from cygwin and msdos shell.

      Ch shell cygwin or unix shell in windows MSDOS shell
    working directory c:/Users/username /c/Users/username c:\Users\username
More examples
  • Example 1
    The following Ch shell script can be used to backup file systems.
      #include<stdio.h>
      int main () {
        printf("Hello, world!\n");
        echo Ch is cool! I can now use a C program to backup files
        dump 0ubdsf 80 50000 50000 /dev/nrst0 /dev/sd0a
      }
    
  • Example 2 with Read eval print loop (REPL) features.
    double x;
    x = 2.5;
    x = streval("2*x")
    printf("x = %.2lf\n", x);
    

    The output is 5.00.

  • Example 3
    The example below will print out all sub-directories and files in the current directory, as well as the full command path for command gzip.
    
         #!/bin/ch
         #include <stdio.h>
         char *s;
         int i=0;
         foreach (s;`ls`) {
            i++;
            echo $s;
         }
         printf("the total number of directory and files are %d\n",i);
         s =`which gzip`;
         echo $s;
    
    

  • Example 4
    Below is another sample shell script.
      #!/bin/ch
      int main() {
        char *s = "pointer to char";
        int i; 
        float f, *p;
        f = 6; 
        p= &f;
        printf("s = %s\n", s);
        printf("*p = %f\n", f);
        /* output from the following statement is "6 6 pointer to char o" */
        echo $f $(*p) $s $(*(s+1));
        pwd
        ls > junk
      }
    
  • Example 5
    The following shell commands in Bourne Shell sh #!/bin/sh command argument << EOF input from the console command line abcd EOF can be handled in Ch as follows: #!/bin/ch #include <stdio.h> FILE *fp; string_t command_args="input from the console command line\nabcd"; fp = popen("command", "w"); fwrite(command_args, strlen(command_args), sizeof(char), fp); pclose(fp);
  • Example 6
    List all commands available anywhere in your path in Unix. #!/bin/ch #include <unistd.h> string_t dir, file; /* define string type */ foreach (dir; `echo $PATH | tr ":" " "`) { foreach (file; `ls $dir`) { if (access (dir/file, X_OK) ==0 ) { echo $dir/$file; } } }
  • Example 7
    Find and compile all .c files into .o in the current directory when the .o is old or absent. #!/bin/ch #include <sys/stat.h> struct stat cstat, ostat; string_t c, o; foreach (c; `find . -name "*.c"`) { o=`echo $c | sed 's/.c$/.o/'`; stat(o, &ostat); stat(c, &cstat); if (ostat.st_mtime > cstat.st_mtime) { echo "compiling $c to $o"; gcc -c -o "$o" "$c"; } }
  • Example 8
    Uses awk in Ch shell. cat file_name | awk "{print \$1}" awk "{print \$1}" < file_name
Note: This article is also translated to Serbo-Croatian language by WHG Team.