return (((ulong*)(x))[-1])


  1. #include "u.h"
  2. #include "lib.h"
  3. ulong
  4. getcallerpc(void *x)
  5. {
  6.     return (((ulong*)(x))[-1]);
  7. }

((ulong*)(x))  将void* 的x针针强制转换为 ulong* 

[-1] : 表示去x前面的那个元素 


ulong px=(ulong*)x 
return (*px) 

一般情况下不会用 下表-1,估计此处有什么特殊用法,要看实际是怎么用的了.


ulong getcallerpc(void *x) 

    return (((ulong*)(x))[-1]); 

在((ulong*)(x))[-1] 中: 

NULL Pointer Bugs

NULL Pointer Bugs

A NULL character pointer is NOT the same as a pointer to a NULL string. In Solaris, the following program will lead to a "Segmentation Fault".

  1. #include <stdio.h>
  2. #include <string.h>
  3. int main()
  4. {
  5.     char *string=NULL;
  6.     printf("/n String length=%d",strlen(string));
  7.     return 0;
  8. }

I don't know hwy this happens clearly now, and it should be pay more attention.

Korn Shell Notes(V)

 19. Input/Output Commands

19.1 Escape Characters

The /c escape character causes the trailing newline to be dropped from the output. It is often used to create prompts.
    $ print "Enter choice: /c"
    Enter choice: $
Notice that the command prompt was displayed following the argument, and not on the next line.

19.2 print Options

19.3 The exec Command

The exec command is used to perform I/O redirection with file descriptors 0 through 9 using this format:
        exec I/O-redirection-command
The I/O redirection performed by the exec command stays in effect until specifically closed, changed, or if the script or shell terminates.

Here, file redir.out is opened as file descriptor 5 for reading and writing:
    $ exec 5<>redir.out
Now the print command writes something to file descriptor 5:
    $ print —u5 "This is going to fd 5"
and the cat command reads from it:
    $ cat <&5

    This is going to fd 5
To finish up, we use another exec to close file descriptor 5:
$ exec 5<&—

Standard input can be taken from a file like this:
    exec 0<file
Commands could be read in from file, and it would be almost as if you typed them at your terminal.

19.4 The read Command

The read command is used to read input from a terminal or file. The basic format for the read command is:
        read variables
where a line is read from standard input. Each word in the input is assigned to a corresponding variable, so the first variable gets the first word, the second variable the second word, and so on. Here, "This is output" is read in to the variables X, Y, and Z. The first word of the input is This, so it is assigned to the first variable X. The second word is is, so it is assigned to the second variable Y. The third word is output, so it is assigned to Z.
    $ print "This is output" | read X Y Z
    $ print $X
    $ print $Y
    $ print $Z

If there aren't enough variables for all the words in the input, the last variable gets all the remaining words.
 This command is the same as the last one, except that an extra string "again" is given.
    $ print "This is output again " | read X Y Z
    $ print $X
    $ print $Y
    $ print $Z
    output again

19.4.1 Reading Input from Files

The read command by itself will only read one line of input, so you need a looping command with it. To read in the contents of a file, use this format:
        exec 0<file
        while read 

The exec command opens file for standard input, and the while command causes input to be read a line at a time until there is no more input.

Here is an alternate format that will also work for reading input from files:
        cat file | while read variable

On the systems tested, the exec format for reading input from files was about 40-60 times faster than the last version above.

19.4.2 The IFS Variable

The read command normally uses the IFS (Internal Field Separator) variable as the word separators. The default for IFS is space, tab, or snewline character, in that order, but it can be set to something else.
By setting IFS to :, the fields in the /etc/passwd file could be read into separate variables.
    $ cat ifs_test
    exec 0</etc/passwd
        print "Account name= $NAME
    Home directory= $HOME
    Login Shell= $SHELL"

19.4.3 Reading Input Interactively

The read command allows input to be read interactively using this format:
        read name?prompt
prompt is displayed on standard error and the response is read into name.

So instead of using two commands to display a prompt and read the input:
    $ print —n "Enter anything: "
    $ read ANSWER
The same thing can be done with one command.
    $ read ANSWER?"Enter anything: "
    Enter anything: ANYTHING
Here is ANSWER:
    $ print $ANSWER

19.4.4 The REPLY variable

If no variables are given to the read command, the input is automatically assigned to the REPLY variable. Here, ANYTHING is read into REPLY:
    $ print ANYTHING | read
    $ print $REPLY

20 Miscellaneous Programming Features

20.1 The . Command

The . command reads in a complete file, then executes the commands in it as if they were typed in at the prompt. This is done in the current shell, so any variable, alias, or function settings stay in effect. It is typically used to read in and execute a profile, environment, alias, or functions file. Here the .profile file is read in and executed:
$ . .profile

The following example illustrates the difference between executing files as Korn shell scripts and reading/executing them using the .command. The .test file sets the variable X:
    $ cat .test
When the .test file is executed as a Korn shell script, variable X is not defined in the current environment, because scripts are run in a subshell:
    $ ksh .test
    $ print $X
After the .test file is read in and executed using the . command, notice that the variable X is still defined:
    $ . .test
    $ print $X
The standard search path, PATH, is checked if the file is not in the current directory.

20.2 Functions

Functions are most efficient for commands with arguments that are invoked fairly often, and are defined with the following format:

        function name {

To maintain compatibility with the Bourne shell, functions can also be declared with this POSIX-style format:
        function-name() {

These types of functions have many limitations compared to Korn shell style functions, such as no support for local variables.

20.3 Scope & Availability

By default, functions are not available to subshells. This means that a regular function that was read in your working environment, .profile file, or environment file would not be available in a Korn shell script.

To export a function, use the typeset -fx command:
        typeset -fx function-name

To make a function available across separate invocations of the Korn shell, include the  typeset -fx function-name command in the environment file.

20.4 Function Variables

All function variables, except those explicitly declared locally within the function with the typeset command, are inherited and shared by the calling Korn shell script. In this example, the X, Y, and Z variables are set within and outside of the function f:

    $ cat ftest
    function f {
        typeset Z=4
        print "In function f, X=$X, Y=$Y, Z=$Z"
    print "Outside function f, X=$X, Y=$Y, Z=$Z"

Notice that when executed, all the variable values are shared between the function and calling script, except for variable Z, because it is explicitly set to a local function variable using the typeset command.
The value is not passed back to the calling Korn shell script:
    $ ftest
    In function f, X=1, Y=2, Z=4
    Outside function f, X=3, Y=2, Z=

The current working directory, aliases, functions, traps, and open files from the invoking script or current environment are also shared with functions.

20.5 Displaying Current Functions

The list of currently available functions are displayed using the typeset -f command.

20.6 Autoloading Functions

To improve performance, functions can be specified to autoload. This causes the function to be read in when invoked, instead of each time a Korn shell script is invoked, and is used with functions that are not invoked frequently. To define an autoloading function, use the typeset -fu function-name command. Here, lsf is made an autoloading function:
    $ typeset —fu lsf

The autoload alias can also be used to define an autoloading function. On most systems, it is preset to typeset -fu.

The FPATH variable which contains the pathnames to search for autoloading functions must be set and have at least one directory for autoloading functions to work.

20.7 Discipline Functions

Discipline functions are a special type of function used to manipulate variables. They are defined but not specifically called. Rather, they are called whenever the variable associated with the function is accessed.

There are some specific rules as to how discipline functions are named and accessed. First of all, discipline functions are named using this syntax:

Notice the the funcion has two parts separated with a dot. The first part name corresponds to the name of a variable, and the second part must be getset, or unset. These correspond to the following operations on the variable:

  • get     whenever the base discipline variable is accessed
  • set     whenever the base discipline variable is set
  • unset     whenever the base discipline variable is unset

For example, the discipline function LBIN.get, LBIN.set, LBIN.unset is called whenever the variable LBIN is accessed, set, or unset.

All three discipline functions are optional, so not all need to be specified. Within a discipline function, the following special reserved variables can be used:

  •     name of current variable
  • .sh.value     value of the current variable
  • .sh.subscript     name of the subscript (if array variable)

From a practical perspective, discipline functions are often used to help debug by tracing the setting and current value of variables in running scripts. Here is a function that can be used to trace setting the value of X:
    function X.set {
        print "DEBUG: ${} = ${.sh.value}"

Discipline functions are also a good place to centralize your variable assignment validation rules. Here is a function that checks to make sure that X it set ao a number between 3 and 10:
    function X.set {
        if (( .sh.value<3 || .sh.value >10 ))
            print "Bad value for ${}: ${.sh.value}"

Note that builtin functions can also be used as additional discipline functions.

20.8 FPATH

The FPATH variable contains a list of colon-separated directories to check when an autoloading function is invoked. It is analogous to PATH and CDPATH, except that the Korn shell checks for function files, instead of commands or directories. Each directory in FPATH is searched from left-to-right for a file whose name matches the name of the function. Once found, it is read in and executed in the current environment. With the following FPATH setting, if an autoloading function lsf was invoked, the Korn shell would check for a file called lsf in /home/anatole/.fdir, then /etc/.functions, and if existent, read and execute it:

    $ print $FPATH

There is no default value for FPATH, so if not specifically set, this feature is not enabled.

20.9 Removing Function Definitions

Functions are removed by using the unset -f command. Here, the rd function is removed:
    $ unset -f rd

20.10 Traps

The trap command is used to execute commands when the specified signals are received.
        trap commands signals

Trap commands are useful in controlling side effects from Korn shell scripts. For example, if you have a script that creates a number of temporary files, and you hit the <BREAK> or <DELETE> key in the middle of execution, you may inadvertently leave the temporary files. By setting a trap command, the temporary files can be cleaned up on an error or interrupt.

The trap_test script creates some files, then removes them when an interrupt is received. Notice that the trap command is surrounded in single quotes. This is so that the FILES variable is evaluated when the signal is received, not when the trap is set.
    $ cat trap_test
    trap 'print "$0 interrupted - removing temp files" ;/
    rm —rf $FILES; exit 1' 1 2
    FILES="a b c d e f"
    touch $FILES
    sleep 100
    $ trap_test
    trap_test interrupted - removing temp files

If an invalid trap is set, an error is generated.

20.10.1 Ignoring Signals

The trap command can be used to ignore signals by specifying null as the command argument:
        trap  ""  signals
This could be used to make all or part of a Korn shell script uninterruptable using normal interrupt keys like Ctl-c.

20.10.2 Resetting Traps

The trap command can also be used to reset traps to their default action by omitting the command argument:
    trap - signals
    trap signals

20.10.3 Exit & Function Traps

A trap can be set to execute when a Korn shell script exits. This is done by using a 0 or EXIT as the signals argument to the trap command:
        trap 'commands0
        trap '
This could be used to consolidate Korn shell script cleanup functions into one place.

20.10.4 Trap Signal Precedence

If multiple traps are set, the order of precedence is:

  • ERR
  • Signal Number
  • EXIT

20.10.5 Trapping Keyboard Signals

The Korn shell traps KEYBD signals (sent when you type a character) and automatically assigns the following reserved variables:

  • .sh.edchar     contains last character of key sequence
  • .sh.edtext     contains current input line
  • .sh.edmode     contains NULL character (or escape character is user in command mode)
  • .sh.edcol     contains position within the current line

20.11 Debugging Korn Shell Scripts

The Korn shell provides a number of options that are useful in debugging scripts: noexecverbose, and xtrace. The noexec option causes commands to be read without being executed. It is used to check for syntax errors in Korn shell scripts. The verbose option causes the input to be displayed as it is read. The xtrace option causes the commands in a script to be displayed as they are executed.

20.11.1 Debugging with trap

The trap command can also be helpful in debugging Korn shell scripts. The syntax for this type of trap command is:
        trap commands DEBUG
        trap commands ERR

20.12 Co-Processes

Co-processes are commands that are terminated with a |& character. They are executed in the background, but have their standard input and output attached to the current shell. The print -p command is used to write to the standard input of a co-process, while read -p is used to read from the standard output of a co-process. Here, the output of the date command is read into the DATE variable using the read -p command:
    $ date |&
    [2] 241
    $ read —p DATE
    $ print $DATE
    Thu Jul 18 12:23:57 PST 1996
Co-processes can be used to edit a file from within a Korn shell script.


Korn Shell Notes(IV)

16 The Environment


variable is provided to make directory navigation easier. It contains a
list of colon-separated directories to check when a full pathname is
not given to the cd command. Each directory in CDPATH is searched from
left-to-right for a directory that matches the cd argument. A : alone
in CDPATH stands for the current directory.

16.2 PATH

variable contains a list of colon-separated directories to check when a
command is invoked. Each directory in PATH is searched from
left-to-right for a file whose name matches the command name. If not
found, an error message is displayed. A : alone in PATH specifies to
check the current directory.

16.3 TMOUT

The TMOUT variable specifies the number of seconds that the Korn shell
will wait for input before displaying a 60-second warning message and
exiting. If not set, the default used is 0, which disables the timeout
feature. To set a 10-minute timer, set TMOUT to 600:
    $ TMOUT=600
This variable is usually set by the system administrator in the /etc/profile file.


MAILCHECK variable specifies how often, in seconds, to check for new
mail. If not set, or set to zero, new mail is checked before each new
prompt is displayed. Otherwise, the default setting is 600 seconds (10

16.5 MAIL

The MAIL variable contains the name of a single mailbox file to check for new mail. It is not used if MAILPATH is set.


MAILPATH variable contains a colon-separated list of mailbox files to
check for new mail and is used if you want to read multiple mailboxes.
It overrides the MAIL variable if both are set. This MAILPATH setting
specifies to check two mailbox files, /home/anatole/mbox and /news/mbox.
    $ print $MAILPATH


so you don't think you can go snooping around someone else's mailbox,
this only works if you have read permission on the mailbox file.
If MAILPATH is not set, there is no default.

16.7 TERM

TERM variable specifies your terminal type, and is usually set by your
system administrator in the global /etc/profile file. If it's not set
there, then it's probably in your ~/.profile file.

16.8 Enabling/Disabling Options

Korn shell options are enabled with the set -ooption or set -option command. For example, the noglob option disables file name substitution and can be set using either of these commands :
    $ set —f


    $ set —o noglob
Options can also be enabled by specifying them on the ksh command line.
Here, a Korn subshell is started with the emacs option enabled:
    $ ksh —o emacs
Options can be disabled with the set +o option or set +option command. In this example, the noglob option is disabled:
    $ set +o noglob

16.9 Displaying the Current Settings

The setting of the current options is displayed with the set -o command.

16.10 Aliases

are command name macros used as shorthand for other commands,
especially frequently used ones. This saves a lot of typing time.
Aliases are defined with the alias name=value
command.Make sure to
enclose the value in quotes if it contains whitespace. Here we create
an alias l that is set to the ls -Fac command:
    $ alias l="ls —Fac"
Now when you type in l, ls -Fac is executed:
    $ l






    . . .

Alias values can contain any text, including special characters, like wild-cards, pipes, or I/O redirection operators.

Here we set two aliases: p and h. When invoked, we get h instead of Hello.
    $ alias p='print' h=Hello

    $ p h

After the p alias is reset with a trailing blank, h gets substituted in the next command correctly:
    $ alias p='print ' h=Hello

    $ p h


16.10.1 Displaying Current Aliases

A list of the current aliases is displayed using the alias command without arguments.

16.10.2 Removing Aliases

Aliases are removed with the unalias command. Let's try it with the l alias:
    $ unalias l

17 Korn Shell Scripts

17.1 Positional Parameters

parameters are special variables used to keep track of arguments to the
Korn shell, scripts, and functions. Positional parameter names contain
only digits and cannot be set directly using variable=value syntax. By default, parameter zero (or $0) is set to the name of the shell, script or function.
    $ print $0

The remaining parameters 1 to n are set to each of the arguments passed
to the shell, script or function. For example, if you invoke a Korn
shell script called ptest and pass the arguments A, B, and C, then in the script ptest, $0 would be set to ptest, $1 to A, $2 to B, and $3 to C.

There are three special Korn shell variables that provide information about the current positional parameters. The first is $#, and it contains the number of positional parameters. The other two are $@ and $*, and they both contain all the positional parameters.
So in the above ptest example, $# would be 3, and both $* and $@ would
be A B C. Here is a Korn shell script that manipulates positional
parameters. It displays the name of the current script, the number of
positional parameters, and the value of each of the positional
    $ cat check_params

    print "Script name: $0"

    print "Number of args passed: $#"

    print "Arguments passed: $*"

    print "Arg 1=$1, Arg 2=$2, Arg 3=$3"

17.2 Modifying Positional Parameters

By default, $0 is set to the name of the shell, script or function. It cannot be set or modified. The remaining parameters from $1 to $n can be reassigned with the shift
command. The shift command, with no arguments, shifts positional
parameters left once, so that $1 takes the value of $2, $2 takes the
value of $3, and so on. The original value of $1 is lost.
Let's change the check_params script so that it shifts the positional
parameters left once:
    $ cat check_params

    print "Script name: $0"

    print "Number of args passed: $#"

    print "Arguments passed: $*"

    print "Arg 1=$1, Arg 2=$2, Arg 3=$3"


    print "Number of remaining args: $#"

    print "Remaining args: $*"

    print "Arg 1=$1, Arg 2=$2, Arg 3=$3"
When we run it again with the arguments A B:
    $ check_params A B

    Script name: check_params

    Number of args passed: 2

    Arguments passed: A B

    Arg 1=A, Arg 2=B, Arg 3=

    Number of remaining args: 1

    Remaining args: B

    Arg 1=B, Arg 2=, Arg 3=
After the shift command, $1 is set to B and $2 is unset. The original value of $1 is lost.

The positional parameters can be shifted left more than once by providing an integer argument to the shift command: shift n.

17.3 The exit command

The exit command allows you to terminate execution from anywhere in a Korn shell script and return an exit value using this format:
        exit n
where n is the exit status to return. If n is not specified, the exit status of the previous command is used. If you don't use exit, then scripts finish after the last command is executed.

17.4 The [[...]] Command

[[...]] command is used to evaluate conditional expressions with file
attributes, strings, integers, and more. The basic format is:
        [[ expression ]]
is the condition you are evaluating. There must be whitespace after the
opening brackets, and before the closing brackets. Whitespace must also
separate the expression arguments and operators. For example, these are

    [[$X = $Y]]
while this is correct:
    [[ $X == $Y ]]
Notice that there is white space between $X, $Y, and the = operator.

If the expression evaluates to true, then a zero exit status is
returned, otherwise the expression evaluates to false and a non-zero
exit status is returned.

If you are familiar with the test and [...]
commands, then you'll recognize that [[...]] is just a new and improved
version of the same commands. It basically functions the same way,
except that a number of new operators are available.

17.4.1 Checking Strings

We could use the [[...]] command to check if a variable is set to a
certain value. Here, variable X is assigned abc, then evaluated in this
    $ X=abc

    $ [[ $X = abc ]] && print "X is set to abc"

    X is set to abc
Using the test and [...] commands, the same command could be written as:
    test "$X" = abc && print "X is set to abc"
    [ "$X" = abc ] && print "X is set to abc"

To check if a variable is set to null, the -z option can be used:
    [[ —z $VAR ]] && print "VAR is set to null"
or it could be compared to the null string like this:
    [[ $VAR = "" ]] && "VAR is set to null"

17.4.2 Checking Patterns

The Korn shell also lets you compare strings to patterns. We could check if X begins with a 'a' like this:
    $ X=abc

    $ [[ $X = a* ]] && print "$X matches a*"

    abc matches a*

Using the +([0–9]) pattern, we could check if X is set to a number:
    $ X=123

    $ [[ $X = +([0—9]) ]] && print "$X is a number"

    123 is a number

17.4.3 Checking File Attributes

The most basic operation to perform on a file is to see if it exists, and that can be done using the -a operator.
    $ touch tmp

    $ [[ —a tmp ]] && print "File tmp exists"

    File tmp exists

This only indicates that it exists, but not much else. It may be a
directory, or a symbolic link, but using this operator, that's all we
know. If we wanted more information, the -f or -d operators could tell
us if a file existed and was a regular file (-f) or if it was just a
directory (-d).

17.4.4 Checking Integer Attributes

The [[...]] command provides a few integer operators that allow
integers to be compared. It is frequently used to check the number of
command-line arguments. This expression evaluates to true if there are
less than or equal to three positional parameters set:
[[ $# —le 3 ]] && print "3 or less args given"

The ((...)) command offers the same arithmetic comparison operators as
the [[...]] command, plus many others. Besides offering more arithmetic
operators, the ((...)) command provides substantial performance
improvements over the [[...]] and test commands.

17.4.5 The ! Operator

The ! operator negates the result of any [[...]] expression when used like this:
[[ ! expression ]]
For example, to check if X is not equal to abc:
    $ X=xyz

    $ [[ ! $X = abc ]] && print "$X not equals abc"

    xyz not equals abc

There is one logical operator that can only be implemented with the !
operator. There is no [[...]] file operator that will evaluate to true
on a zero-length file.
    $ >emptyfile

    $ [[ ! —s emptyfile ]] && print "emptyfile is empty"

    emptyfile is empty

17.4.6 Compound Expressions

(1) && - The AND Operator
The && operator is used with the [[...]] command to test if multiple expressions are true using this format:
    [[ expression1 && expression2 ]]

This expression checks if the noglob and noclobber options are set:
    [[ —o noglob && —o noclobber ]]

(2) || - The OR Operator
The | | operator is used with the [[...]] command to test if expression1 OR expression2 are true using this format:
    [[ expression1 | | expression2 ]]

17.4.7 [ [...] ] vs test and [...]

The [[...]] command is preferred to test and [...], since many of the errors associated with test and [...] do not occur.

18 Control Commands

18.1 The case command

The case command provides multiple-branch capability. The syntax for the case command is:

where value is compared to pattern1, pattern2, ... patternn.

same patterns used in file name substitution can also be used in case
statements to match patterns. The new Korn shell pattern matching
formats also allow multiple case patterns to be given like this:

18.2 The for Command

The basic syntax for the for command is:
        for variable in word1  word2 . . . wordn

File name substitution, command substitution, and variable substitution
can also be used to generate a list of word arguments for the for
command. The first line of the previous command could have been given
    for FILE in chap[1-3]
    for FILE in $(ls chap[1-3])
    CHAPS=$(ls chap[1-3])
    for FILE in $CHAPS

The $* and $@ variables can be used to loop on command-line arguments like this:
        for variable in $*

The for command can also be used without the list of word arguments:
        for variable




The commands are executed once for each positional parameter, and variable is set to each successive positional parameter. It is equivalent to:
       for variable in $@




18.3 The if Command

The basic syntax of the if command is:
        if command1
elif command2

18.4 The while Command

        while command1

18.5 The until Command

until command is another looping command. It's like the while command,
except that instead of looping while the condition is true, it loops
while the condition is false. The syntax for the until command is:
        until command1

where commands are executed until command1 returns a zero exit status.

18.6 Breaking Out of Loops

break command  causes an exit from a loop-type command, but not from the entire script.

The break command can also be used to exit from a nested loop using this format:
        break n
where  n specifies the nth enclosing loop to exit from.
Here is a new version of the nloop script that breaks out of both loops if i equals 2 and j equals 0:
$ cat nloop
for i in 1 2 3
    for j in 0 5
        if ((i == 2 && j == 0))
            break 2
            print "$i$j"

Now the output would be:
    $ nloop
break was used instead of break 2, then only the inner for loop would
have been terminated, and execution would have continued with i set to
3 in the outer loop, and j set to 0 in the inner loop.

18.7 The continue Command

The continue command causes execution to continue at the top of the current loop.

18.8 The select Command
The select command
is used to display a simple menu that contains numbered items, and a
prompt message. The syntax for the select command is:

        select variable in word1 word2 . . . wordn

where word1 through wordn are displayed as numbered menu choices followed by a prompt (default #?).

If the response is in the range 1 through n, then variable is set to the corresponding word, REPLY is set to the response, and the commands are executed. Execution continues until a break, exit, return, or EOF is encountered.

18.8 The select Command

select command is used to display a simple menu that contains numbered
items, and a prompt message. The syntax for the select command is:

        select variable in word1 word2 . . . wordn




where word1 through wordn are displayed as numbered menu choices followed by a prompt (default #?). If the response is in the range 1 through n, then variable is set to the corresponding word, REPLY is set to the response, and the commands are executed. Execution continues until a break, exit, return, or EOF is encountered.

The select command can also be used without the list of word arguments:

       select variable




functions the same way as the previous select syntax, except that the
positional parameters are displayed as numbered menu choices from 1 to
n, instead of the words from the word list. It is equivalent to:
       select variable in "$@"




korn Shell Notes(III)

 6 Variables

The Korn shell supports four data types: string, integer, float, and array. If a data type is not explicitly defined, the Korn shell will assume that the variable is a string.

The typeset command can also be used to assign values.

If a value is not given, the variable is set to null. Here, X is reassigned the null value:
    $ X=

6.1 Variable Attributes

Korn shell variables can have one or more attributes that specify their internal representation, access or scope, or the way they are displayed.Variables can be set to integer type for faster arithmetic operations, read-only so that the value cannot be changed, left/right justified for formatting purposes, and more. To assign a value and/or attribute to a Korn shell variable, use the following format with the typeset command:
    typeset-attribute variable=value
    typeset-attribute variable

Except for readonly, variable attributes can be set before, during, or after assignment. Functionally it makes no difference. Just remember that the attribute has precedence over the value. This means that if you change the attribute after a value has been assigned, the value may be affected.

6.2 Lowercase (-l) and Uppercase (-u) Attributes

These attributes cause the variable values to be changed to lower or uppercase. For example, the lowercase attribute and uppercase value ASPD are assigned to variable MYSYS:
    $ typeset —l MYSYS=ASPD
Despite the fact that MYSYS was assigned uppercase ASPD, when accessed, the value is displayed in lowercase:
    $ print $MYSYS

This is because the attribute affects the variable value, regardless of the assignment. Variable attributes can also be changed after assignment. If we wanted to display variable MYSYS in uppercase, we could just reset the attribute:
    $ typeset —u MYSYS
    $ print $MYSYS

6.3 Readonly (-r) Attribute

Once the readonly attribute is set, a variable cannot be assigned another value. Here, we use it to set up a restricted PATH:
    $ typeset —r PATH=/usr/rbin
If there is an attempt to reset PATH, an error message is generated:
    $ PATH=$PATH:/usr/bin:
    /bin/ksh: PATH: is read only

Unlike other variable attributes, once the readonly attribute is set, it cannot be removed.

6.4 Integer (-i) Attribute

The integer attribute (-i) is used to explicitly declare integer variables. Although it is not necessary to set this attribute when assigning integer values, there are some benefits to it.

There is one restriction on integer variables. Once a variable is set to integer type, it can't be assigned a non-integer value:
    $ typeset —i NUM=abc
    /bin/ksh: NUM: bad number

6.5 The Float (-E, -F) Attribute

The float attributes (-E, -F) are used to declare float variables. The -E is used to specify the number of significant digits, while -F is used to specify the precision. In the following example, X is set to a float variable and assigned a value using both formats:
    $ typeset —E5 X=123.456
    $ print $X
    $ typeset —F5 X=123.456
    $ print $X
The float command can also be used to declare a float variable, but does not allow for specifying the precision.

6.6 Right (-R) and Left (-L) Justify Attributes

The right and left justify attributes cause variable values to be justified within their width and are be used to format data. Here, variables A and B are set to right-justify with a field width of 7 characters. Notice that integer values are used, even though the integer attribute is not set.

If the field width is not large enough for the variable assignment, the value gets truncated. Variable X is assigned a seven-character wide value, but the field width is set to 3, so the first four characters are lost:
    $ typeset —R3 X=ABCDEFG
    $ print $X

If a field width is not given, then it is set with the first variable assignment. Variable Y is assigned a three-character wide value, so the field width is set to 3.
    $ typeset —L Y=ABC
    $ print $Y
Without explicitly resetting the field width, a subsequent assignment would be restricted to a three-character wide value:
    $ print $Y

6.7 Autoexport (-x) Attribute

It allows you to set and export a variable in one command. Instead of
    $ typeset X=abc
    $ export X
you can do this:
    $ typeset —x X=abc
We could use this attribute to add the /lbin directory to the PATH variable and export it all in one command:
    $ typeset —x PATH=$PATH:/lbin

6.8 Removing Variable Attributes

Except for readonly, variable attributes are removed with the typeset +attribute command. Assuming that the integer attribute was set on the NUM variable, we could remove it like this:
    $ typeset +i NUM
and then reassign it a non-integer value:
    $ NUM=abc

Once the readonly attribute is set, it cannot be removed. When we try to do this with the PATH variable that was previously set, we get an error message:
    $ typeset +r PATH
    /bin/ksh: PATH: is read only
The only way to reassign a readonly variable is to unset it first, then assign a value from scratch.

6.9 Checking Variable Attributes

Attributes of Korn shell variables are listed using the typeset -attribute command. For example, to list all the integer type variables and their values:
    $ typeset —i

To list only the names of variables with a specific attribute, use the typeset +attribute command.

6.10 More with Variables

You can do other things with variables, such as assign them the value of another variable, the output of a command, or even the contents of a file.

Variables can be assigned command output using this format:

The second format is provided for compatibility with the Bourne shell. Here, UCSC is set to its internet ID by assigning the output of the grep and cut commands:
    $ UCSC=$(grep UCSC /etc/hosts | cut —f1 —d" ")
    $ print $UCSC

Variables can also be assigned the contents of files like this:
    variable=`cat file`
The first format is equivalent to variable=$(cat file). The second format is much slower, but is provided for compatibility with the Bourne shell.

nameref variable is a synonym for another variable and will always have the same value as its associated variable They are created using the following formats:
    nameref nameref_variable=variable
    typeset -n nameref_variable=variable
For example:
    $ X=abc
    $ nameref Y=X
    $ print $X
    $ print $Y

6.11 Unsetting Variables

Variable definitions are removed using the unset command. This is not the same as being set to null.

Unsetting either the base or nameref variable will unset both variables.

7 Special Parameters

7.1 The ? Parameter

The ? parameter contains the exit status of the last executed command. In this example, the date command is executed. It ran successfully, so the exit status is 0:
    $ date +%D
    $ print $?
When used with a pipe, $? contains the exit status of the last command in the pipeline.

7.2 The $ Parameter

The $ parameter contains the process id of the current shell.
    $ print $$

It is useful in creating unique file names within Korn shell scripts.
    $ touch $0.$$
    $ ls *.*

7.3 Other Special Parameters

The - parameter contains the current options in effect. The output of the next command shows that the interactive and monitor options are enabled:
    $ print $—

To display the error number of the last failed system call, use the ERRNO variable. Here, an attempt to display a non-existent file returns an error, so ERRNO is checked for the error number:
    $ cat tmp.out
    tmp.out: No such file or directory
    $ print $ERRNO
This is system dependent, so it may not be available on your system. Check your documentation or /usr/include/sys/errno.h for more information.

8 Variable Expansion

Variable expansion is the term used for the ability to access and manipulate values of variables and parameters. Basic expansion is done by preceding the variable or parameter name with the $ character. This provides access to the value.
    $ UULIB=/usr/lib/uucp
    $ print $UULIB

Other types of expansion can be used to return portions or the length of variables, use default or alternate values, check for mandatory setting, and more.

For the sake of convenience, the term variable will refer to both variables and parameters in the following sections that discuss variable expansion.

8.1 $variable, ${variable}

This is expanded to the value of variable. The braces are used to protect or delimit the variable name from any characters that follow. The next example illustrates why braces are used in variable expansion. The variable CA is set to ca:
    $ CA=ca

What if we wanted to reset CA to california? It could be reset to the entire value, but to make a point, let's try using the current value like this:
    $ CA=$CAlifornia
    $ print $CA

Nothing is printed, because without the braces around the variable CA, the Korn shell looks for a variable named $CAlifornia. None is found, so nothing is substituted. With the braces around variable CA, we get the correct value:
    $ CA=${CA}lifornia
    $ print $CA

Braces are also needed when attempting to expand positional parameters greater than 9. This ensures that both digits are interpreted as the positional parameter name.

8.2 ${#variable}

This is expanded to the length of variable. In this example, X is set to a three-character string, so a length of 3 is returned:
    $ X=abc
    $ print ${#X}
Whitespace in variable values is also counted as characters.

8.3 ${variable:-word}, ${variable-word}

This is expanded to the value of variable if it is set and not null, otherwise word is expanded. This is used to provide a default value if a variable is not set. In the following example, the variable X is set to abc. When expanded using this format, the default value abc is used:
    $ X=abc
    $ print ${X:—cde}
After X is unset, the alternate value cde is used:
    $ unset X
    $ print ${X:—cde}
Notice that the value of X remains unchanged:
$ print $X

Let's say we needed a command to get the user name. The problem is that some people have it set to USER, while others have it set to LOGNAME. We could use an if command to check one value first, then the other. This would be quite a few lines of code. Or we could use this form of variable expansion to have both values checked with one command. Here, if USER is set, then its value is displayed, otherwise the value of LOGNAME is displayed.
    USER=anatole, LOGNAME=AO
    $ print ${USER:—${LOGNAME}}
Now we unset USER to check and make sure that LOGNAME is used:
    $ unset USER
    $ print ${USER:—${LOGNAME}}

But what if both USER and LOGNAME are not set? Another variable could be checked like this:
    $ unset USER LOGNAME
    $ print ${USER:-${LOGNAME:-USER and LOGNAME not set!}}
    USER and LOGNAME not set!
$ print ${USER—${LOGNAME:—$(whoami)}}

Remember that the alternate value is only used and not assigned to anything. The other format, ${variable-word}, causes the variable value to be used, even if it is set to null:
    $ typeset X=
    $ print ${X-cde}

8.4 ${variable:=word}, ${variable=word}

This is expanded to the value of variable if set and not null, otherwise it is set to word, then expanded. In contrast to the variable expansion format from the previous section, this format is used to assign a default value if one is not already set. In the next example, the variable LBIN is set to /usr/lbin. When expanded using this format, the default value /usr/lbin is used:
    $ LBIN=/usr/lbin
    $ print ${LBIN:=/usr/local/bin}

After LBIN is unset, this form of variable expansion causes LBIN to be assigned the alternate value, /usr/local/bin:
$ unset LBIN
$ print ${LBIN:=/usr/local/bin}

Command substitution can also be used in place of word. This command sets the SYS variable using only one command:
    $ unset SYS
    $ print ${SYS:=$(hostname)}

The other format, ${variable=word}causes the variable value to be used, even if it is set to null. Here LBIN is not assigned an alternate value. If := was used instead of =, then LBIN would be set to /usr/local/bin:
    $ LBIN=
    $ print ${LBIN=/usr/local/bin}

8.5 ${variable:?word}, ${variable:?}; ${variable?word}, ${variable?}

This is expanded to the value of variable if it is set and not null, otherwise word is printed and the Korn shell exits. If word is omitted, "parameter null or not set" is printed. This feature is often used in Korn shell scripts to check if mandatory variables are set. In this example, variable XBIN is first unset. When expanded, the default error is printed:
    $ unset XBIN
    $ : ${XBIN:?}
    /bin/ksh: XBIN: parameter null or not set

You could also provide your own error message:
    $ print ${XBIN:?Oh my God, XBIN is not set!}
    /bin/ksh: XBIN: Oh my God, XBIN is not set!

The other formats, ${variable?word} and ${variable?}, cause the variable value to be used, even if it is set to null.

8.6 ${variable:+word }, ${variable+word }

This is expanded to the value of word if variable is set and not null, otherwise nothing is substituted. This is basically the opposite of the ${variable:-word} format. Instead of using word if variable is not set, word is used if variable is set. In the first example Y is set to abc. When expanded, the alternate value def is displayed because Y is set:
    $ Y=abc
    $ print ${Y:+def}

Here, Y is unset. Now when expanded, nothing is displayed:
    $ unset Y
    $ print ${Y:+def}

Like the ${variable:-word} format, the alternate value is only used and not assigned to the variable. Y is still set to null:
    $ print $Y

The other format, ${variable+word}, causes the variable value to be used, even if it is set to null:
    $ Y=
    $ print ${Y+def}

8.7 ${variable#pattern}, ${variable##pattern}

This is expanded to the value of variable with the smallest (#) or largest (##) part of the left matched by pattern deleted. What these expansion formats allow you to do is manipulate substrings. To demonstrate the basic functionality, X is set to a string that contains a recurring pattern: abcabcabc.
    $ X=abcabcabc

When expanded to return the substring that deletes the smallest left pattern abc, we get abcabc:
    $ print ${X#abc*}

while the substring that deletes the largest left pattern abc is abcabcabc, or the entire string:
    $ print ${X##abc*}

We could use this concept to implement the Korn shell version of the UNIX basename command. The pattern in this command causes the last directory to be returned if variable X is set to a full pathname:
    $ X=/usr/spool/cron
    $ print ${X##*/}

8.8 ${variable%pattern}, ${variable%%pattern}

This is expanded to the value of variable with the smallest (%) or largest (%%) part of the right matched by pattern deleted. It could also be used to display file names without their .suffixes:
    $ X=file.Z
    $ print ${X%.*}

The pattern in this command causes it to act like the UNIX dirname command. Everything except the last directory is returned if variable X is set to a full pathname.
    $ X=/usr/spool/cron
    $ print ${X%/*}

8.9 ${variable//pattern1/pattern2}, ${variable/pattern1/pattern2}; ${variable#pattern1/pattern2},${variable/%pattern1/pattern2}

The Korn shell supports four search and replace operations on variables. This example changes all occurrences of abc in X to xyz:
    $ X=abcabcabc
    $ print ${X//abc/xyz}
while this one only changes the first occurrence of abc in X to xyz:
    $ X=abcabcabc
    $ print ${X/abc/xyz}
See Table 3.6 for detailed explanation of the other formats.

8.10 ${variable:start}, ${variable:start:length}

This format returns a substring. The first returns variable from character position start to end, while the second returns length characters from variable from character position start to end. For example, this returns the first 3 characters of X:
    $ X=abcdefghij
    $ print {$X:0:3}
while this example returns the value of X starting at character position 5:
    $ X=abcdefghij
    $ print {$X:5}

9 Array Variables

Arrays can have a maximum of 4096 elements. Array subscripts start at 0 and go up to 4096 (or the maximum element minus one). Any variable can become a one-dimensional array by simply referring to it with a subscript.

9.1 Array Variable Assignments & Declarations

Arrays can be assigned values by using normal variable assignment statements, the set -A command, or the typeset command:
        variable[0]=value variable[1]=value . . . variable[n]=value
        set -A variable value0 value1 . . . valuen
        typeset variable[0]=value variable[1]=value . . .  variable[n]=value

The only difference between the formats, is that with the set command format, the values are assigned to the array variable sequentially starting from element zero. In the other formats, the array elements can be assigned values in any order.

Not all the elements of an array need to exist. You can assign values to non-successive elements of an array.

9.2 Array Variable Expansion

Array variables are expanded in the same manner as normal variables and parameters: using the $ character. Without a subscript value, an array variable refers to the first element, or element 0.

To access the value of a specific array variable element use a subscript. Array variable names and subscripts must be enclosed in braces for proper expansion:
    $ print ${DAY[3]} ${DAY[5]}
    Thu Sat

All the elements of an array can be accessed by using the * or @ as the subscript value. They both return the same value.

The number of elements of an array variable is returned by using the # in front of the array variable name and using * or @ as the subscript value.

To get values for a subset of an array, use this format:

Arithmetic expressions can be used to return a subscript value. Variable expansion can also be used to generate a subscript value.

9.3 Array Variable Attributes

Arrays can also be declared, and assigned values and attributes with the typeset command:
                typeset -attribute variable[0]=value variable[1]=value . . .
Once set, attributes apply to all elements of an array. This example sets the uppercase attribute for the DAY array variable using the typeset -u command:
        $ typeset —u DAY
Now all the element values are displayed in upper case:
        $ print ${DAY[*]} #Pay attention to usage.
Array element attributes can be set before or after assignment.

9.4 Array Variable Reassignments

Besides using regular array-element[n]=value or typeset arrayelement[n]=value syntax to reassign values, array variables can also have their values reassigned with the set +A command:
set +A variable value0 value1 . . .

9.5 Associative Arrays

Associative arrays use string subscripts rather than integer subscripts. Associative arrays are declared using this format:
                typeset -A variable
variable is the name of the associative array. Additional arguments can be given to the typeset command to specify a data type. For example, we can create an associative array to store some exchange rates:
    $ typeset -AE exchange_rate
    $ exchange_rate["DM"]=1.7
    $ exchange_rate["FF"]=.15
    $ exchange_rate["AS"]=.04

To display a list of associative array subscripts:
                ${!variable[*]}  or  ${!variable[@]}
To display the values for all or parts of an associative array:
For example, all and a specific exchange rate is displayed here:
    $ print ${!exchange_rate[*]}
    0.15 1.7
    $ print "The DM exchange rate is:${exchange_rate[DM]}"

10 Compound Variables

Compound Variables is a meta-datatype which is a group of related values. The syntax for declaring compund variables is:
[datatype] field1[=value]
                . . .

The syntax to display the value of a compound variable field is:

11 Quoting

There are three types of quotes: single quotesdouble quotes, and back quotes. Single and double quotes are similar, except for the way they handle some special characters. Back quotes are used for command output assignment.

11.1 Single Quotes

Single quotes are also used to hide the meaning of special characters like $, *, /, !, ", ` and /. Any characters between single quotes, except another single quote, are displayed without interpretation as special characters:
    $ print '* $ / ! ` / "'
    * $ / ! ` / "

Variable and command substitution does not take place within single quotes (because $ and `` lose their special meaning). If you want to access the value of a variable, use double quotes instead of single quotes (discussed in the next section).

Variables can be set to null with single quotes:
    $ X=''
Single quotes are also used to assign values to aliases and trap commands, and prevent alias substitution, but we'll get to that later.

11.2 Double Quotes

Double quotes are like single quotes, except that they do not remove the meaning of the special characters $, `, and /. This means that variable and command substitution is performed.
    $ DB="$HOME:`pwd`"
    $ print $DB

Double quotes also preserve embedded whitespace and newlines. Here are some examples:
    $ print "Line 1
    > Line 2"    #The > is the secondary prompt, and is displayed whenever the Korn shell needs more input.
    Line 1
    Line 2
    $ print "A        B"
    A        B

In this case, it waits for the closing double quote:
    $ ADDR="ASP,Inc
    > PO Box 23837
    > San Jose CA 95153 USA
    > (800)777-UNIX * (510)531-5615"
Without double quotes around ADDR, we get this:
    $ print $ADDR
    ASP,Inc PO Box 23837 San Jose CA 95153 USA (800) 777-
    UNIX * (510)531-5615
Not quite what we wanted. Let's try it again:
    $ print "$ADDR"
    PO Box 23837
    San Jose CA 95153 USA
    (800)777-UNIX * (510)531-5615

There are also other uses for double quotes. You can set a variable to null:
    $ NULL=""
    $ print $NULL
or display single quotes.
    $ print "'This is in single quotes'"
    'This is in single quotes'
If you really wanted to display the $, `, /, or " characters using double quotes, escape them with a backslash like this:
    $ print "/$HOME is set to $HOME"
    $HOME is set to /home/anatole
    $ print "/`=back-quote //=slash /"=double-quote"
    `=back-quote /=slash "=double-quote

11.3 Back Quotes

Back quotes are used to assign the output of a command to a variable. This format, from the Bourne shell, is accepted by the Korn shell but considered obsolescent. This command sets the variable SYS to the system name:
    $ SYS=`uuname —l`
    $ print $SYS

12 Command History File

The Korn shell stores the commands that you enter at your terminal in a file, called the command history file. This file is specified by the HISTFILE variable. If not set, the default is $HOME/.sh_history.

The number of commands accessible via the command history file is specified by the HISTSIZE variable. If not set, the last 128 commands are saved, starting from your most recent command.

There are two ways to access the command history file: using the fc command, or the in-line editor.

13 The fc Command

The fc command allows you to list, or edit and re-execute history file commands. The fc command also allows you to manipulate the history file using your own choice of editors.

13.1 Displaying the Command History File

The format for displaying the command history file with the fc -l command is:
        fc -l[nr] [ range ]
where the -n option causes the command numbers to not be  displayed, and the -r option specifies reverse order (latest commands first). The range of commands to list is given as:
n1 [n2]:     display list from command n1 to command n2. If n2 is not specified, display all the commands from current command back to command n1.
-count:     display the last count commands string display all the previous commands back to the command that matches.
string:     If no range argument is given, the last sixteen commands are listed.

If no range argument is given, the last sixteen commands are listed. Let's look at the last five commands:
    $ fc -l -5
    250 set
    251 vi /etc/env
    252 . /etc/env
    253 set
    254 alias
    255 functions
The history command is equivalent to fc -l. The last command could also be given like this. Notice that the order is reversed.
    $ history —r —5
    255 functions
    254 alias
    253 set
    252 . /etc/env
    251 vi /etc/env
    250 set
By using a string instead of a count argument, we could search backward for a specific command.
    $ history —r set
    258 fc —lr set
    257 fc —ln —10
    256 fc —l 250 265
    255 functions
    254 alias
    253 set
The argument set could also be given as s, or se, since partial strings are also matched. This means that the string f would match functions and fc, while fu would only match functions.

13.2 Editing the Command History File

Besides displaying the command history file, it can also be edited using the fc command with the following format:
                fc [-e editor] [-r] [range]
                fc -e - [old=new] [command]
where the -e editor option is used to specify an editor. If not given, the value of the FCEDIT variable is used, and if not set, the default /bin/ed is used. The -r option reverses the order of the commands, so that the latest commands are displayed first.

Using r, the last command could also be given as: 
    $ r 173

The substitution feature is used to make minor changes to a previous command. Let's start with print Hello:
    $ print Hello
We could change Hello to something else like this.
    $ r Hello=Goodbye print
    print Goodbye

14 Job Control

Job control allows programs to be stopped and restarted, moved between the foreground and background, their processing status to be displayed, and more. To enable the job control feature, the monitor option must be enabled with the set command:
                $ set —o monitor
                $ set —m
This can be put into the .profile file so that job control is automatically enabled at login.

14.1 Manipulating Jobs
Jobs running in the foreground are suspended by typing Ctl-z (Control-z). So instead of waiting for the long-running split command to complete, it is interrupted using Ctl-z:
    $ split —5000 hugefile

    [3] + Stoppedsplit —5000 hugefile

Stopped and backgrounded jobs are brought back into the foreground with the fg command. If no argument is given, the current (most recently stopped or backgrounded) job is used. The stopped split job is brought back into the foreground with fg:
    $ fg
    split —5000 hugefile
    $ fg %3

Stopped jobs are put into the background with the bg command.

14.2 Checking Job Status

The status and other information about all jobs is displayed using the jobs command. The jobs -l command shows the same information, along with the process ids, while jobs -p only gives you the process ids.
    $ jobs —l
    [3] + 466 Stopped split —5000 hugefile
    [2] — 465 Running find / —name core —print &
    [1] 463 Running sleep 25 &

Stopped or background jobs are terminated with the kill command.

You can make the Korn shell wait for some or all background jobs to complete with the wait command. If no argument is given, the Korn shell waits for all background jobs to complete.

14.3 Job Control

Jobs being executed in the background are prevented from generating output by setting stty tostop. Let's run the find job again with the tostop option enabled:
    $ stty tostop
    $ find / —name core —print &
    [2] 1460
The stty tostop command can be put into your profile file so that background job output is by default disabled.

The nohup command can also be used to direct output from background jobs. It causes standard output and standard error to be automatically sent to nohup.out, or whatever file you give it. One added benefit. The nohup command will keep jobs running, even if you log out. Here we run the find job again using nohup. First we need to enable background job output:
    $ stty —tostop
    $ nohup find / —name core —print &
    [2] 1469
    $ wait
    Sending output to 'nohup.out'
    [2] + Done nohup find / —name core —print &
The find job output is in nohup.out:
    $ cat nohup.out

14.4 Job Names

15 Performing Arithmetic

All of the operators from the C programming language (except ++, --, and ?:) are now supported by the Korn shell.

15.1 The let Command

Integer arithmetic can be done with the let command and arithmetic expressions. The format for the let command is:
                let  "arithmetic-expression"
where arithmetic-expressions can contain constants, operators, and Korn shell variables. Double quotes are used with arithmetic expressions that contain white space or operators that have special meaning to the Korn shell.

Notice that in arithmetic expressions, regular variables can be referenced by name only, and do not have to be preceded by $ for substitution to be performed. Both
    $ let "X=X + 1"
    $ let "X=$X + 1"
are equivalent. The first format is preferred because parameter expansion does not have to be performed.

15.2 The ((...)) Command

The ((...)) command is equivalent to the let command, except that all characters between the (( and )) are treated as quoted arithmetic expressions. This is more convenient to use than let, because many of the arithmetic operators have special meaning to the Korn shell. The following commands are equivalent:
    $ let "X=X + 1"
    $ ((X=X + 1))

15.3 Declaring Integer Variables

As with ordinary variables, integer variables need not be declared. A variable can simply be given an integer value, and then used in an arithmetic expression. However, variables can be explicitly declared integer type by using the typeset -i command. There is also another command called integer, which is equivalent to typeset -i.

Arithmetic can be performed directly on integer variables without using the let or ((...)) commands, as long as the integer value is being assigned a value. In other words, you can do this:
    $ integer DAYS="4 + 3"
instead of
    $ ((DAYS=4 + 3))
    $ let "DAYS=4 + 3"

15.4 Arithmetic Constants

The format for arithmetic constants is:
where base is a whole number between 2 and 36, and number is any non-negative integer. If not specified, the default base is 10. The arithmetic base of a variable can be set with the typeset -in command, or by prepending base# to the value. In this example, variable X is set to 5 in base 2 using both formats:
    $ typeset —i2 X=5
    $ typeset —i X=2#101     #Note here 101 denotes 5 in decimal. 

If you want to display the value of X in another base, just reset the base with the typeset -in command. Here it is reset to base 3:
    $ typeset —i3 X
    $ print $X

15.5 Random Numbers

The Korn shell provides a special variable, RANDOM, which is used to generate random numbers in the range from 0 to 32767.

You can also initialize a sequence of random numbers by setting RANDOM to a value. Here, RANDOM is set to 7. When subsequently accessed, the values 2726 and 18923 are returned:
    $ RANDOM=7
    $ print $RANDOM
    $ print $RANDOM
When RANDOM is reset to 7 again, the same numbers are returned:
    $ RANDOM=7
    $ print $RANDOM
    $ print $RANDOM
If RANDOM is unset, the special meaning is removed, even if reset.

16 The Environment

Korn Shell Notes(II)

Korn Shell Notes

1 Useful Cmds

wc - display a count of lines, words and characters in a file.
    It can be used to count the numbers together with other commands, such as ls, who and so on.

cut - cut out selected fields of each line of a file.
    The name of each unique user that is logged on is displayed using this command:
        $ who | cut —f1 —d' ' | sort —u



print is a Korn shell specialized command which is similar to echo.

nl - line numbering filter.

2 Process Execution

2.1 Conditional Execution

You can implement a simple if command by using the && and || operators together like this:
            command1 && command2 || command3
If command1 returns true, then command2 is executed, which causes
command3 to not be executed. If command1 does not return true, then
command2 is not executed, which causes command3 to be executed.

2.2 Grouping Commands

Commands enclosed in {} are executed in current shell. If

        $ echo "This is file temp:" ; cat temp | nl
        This is file temp:
        1 The rain in Spain
        2 falls mainly on the plain
then by using {}s, the output will be:
        $ { echo "This is file temp:"; cat temp ; } | nl
        1 This is file temp:
        2 The rain in Spain
        3 falls mainly on the plain
There must be whitespace after the opening {, and commands within the {}'s must be terminated with a semi-colon.

enclosed in () are executed in a subshell. Subshells are generated
whenever you enclose commands in ()'s, perform command substitution,
for background processes, and for coprocesses.A subshell is a separate
copy of the parent shell, so variables, functions, and aliases from the
parent shell are available to the subshell. However, subshells cannot
change the value of parent shell variables, functions, or aliases.

3 Input/Output Redirection

3.1 Redirecting Standard Output

By using the > symbol, the standard output of a command can be redirected to a file, instead of your terminal.

You can also use the > command to create an empty file:
    $ > tmp
    $ ls —s tmp
    0 tmp
This is equivalent to touch tmp.

Standard output can be appended to a file by using the >> redirect operator.

Standard output is closed with the >&- redirect operator:
    $ echo "This is going nowhere" >&-

3.2 The noclobber Option

prevent redirecting output to an existing file, set the noclobber
option. By default, this feature is usually disabled, but can be
enabled with the set -o noclobber command:
        $ ls > file.out
        $ set —o noclobber

The >| operator is used to force overwriting of a file, even if the noclobber option is enabled.

3.3 Redirecting Standard Input

Standard input to a command is redirected from a file using the < operator.

3.4 Redirecting Standard Error

with standard output, standard error is by default directed to your
terminal, but it can be redirected using the standard error file
descriptor (2) and the > operator, e.g. 2>

3.5 More With File Descriptors

The >&n operator
causes output to be redirected to file descriptor n. This is used when
you want to direct output to a specific file descriptor.In the next
command, the standard error and output are sent to ls.out by specifying
multiple redirections on the same command line. First, >&2
causes standard output to be redirected to standard error. Then,
2>ls.out causes standard error (which is now standard output and
standard error) to be sent to ls.out:
        $ ls tmp t.out 2>ls.out 1>&2
        $ cat ls.out
        tmp not found

the output of the last command was redirected to a file using the >
operator, then only the standard output would be redirected. The
standard error would still be displayed on your terminal.
        $ {echo "This is going to stdout"} >&1;/
        echo "This is going to stderr" >&2;} >out
        This is going to stderr
        $ cat out
        This is going to stdout.

The n>&m operator
causes the output from file descriptors n and m to be merged. This
operator could be used in the previous command to direct both the
standard output and standard error to the same file.

If you wanted the standard output and standard error appended to the output file, the >> operator could be used.

3.6 Here Document

Here documents is a term used for redirecting multiple lines of
standard input to a command. In looser terms, they allow batch input to
be given to programs and are frequently used to execute interactive
commands from within Korn shell scripts. The format for a here document
        command << word
        command <<-word
where lines that follow are used as standard input to command until word is read.

other variation, command <<- word, deletes leading tab characters
from the here document. It is often used over the first variation to
produce more readable code when used within larger scripts. A good use
for here documents is to automate ftp file transfers. This snippet of
code could be used within a larger script to automatically ftp code to
or from another server.

3.7 Discarding Standard Output

  The /dev/null file is like the system trash bin. Anything redirected to it is discarded by the system.

4 File Name Substitution

4.1 The * Character

* matches any zero or more characters in current directory, except
those begin with the "." character. These must be explicitly matched.

4.2 The ? Character

The ? character matches exactly one character.

4.3 The [] Character

The [] characters match a single, multiple, or range of characters.
This command lists file names beginning with d or m, and ending with any number 1 through 5:

the range argument, the first character must be alphabetically less
than the last character. This means that [c-a] is an invalid range.
This also means that pattern [0–-z] matches any alphabetic or
alphanumeric character, [A-z] matches any alphabetic character (upper
and lower case), [0–Z] matches any alphanumeric or upper case
alphabetic character, and [0–9] matches any alphanumeric character.

Multiple ranges can also be given. The pattern [a-jlmr3–-7] would match files names beginning with the letters a through j, l, m, r, and 3 through 7.

4.4 The ! Character

The ! character can be used with [ ] to reverse the match. In other words, [!a] matches any character, except a.
If we want to list all of the file names except those started with d, we could do this:

or it can be done more easily using [!d]:

Multiple and range arguments can also be negated. The pattern [!lro]* would match strings not beginning with l, r, or o, *[!2–5] would match strings not ending with 2 through 5, and *.[!Z] would match strings not ending in .Z.

4.5 Complex Patterns

Korn Shell also provides entire patterns matching.

4.5.1 *(pattern)

This format matches any zero or more occurrences of pattern.

This pattern matches anti, antic, antigen, and antique: $ match anti*(c|gen|que)

4.5.2 ?(pattern)

This format matches any zero or one occurrences of pattern. Here are some more patterns using this format:


4.5.3 +(pattern)

This format matches one or more occurrences of pattern.

4.5.4 @(pattern)

This format matches exactly one occurrence of pattern. Let's look for words beginning with Ala or Cla:     $ match @([AC]la)*

4.5.5 !(pattern)

This format matches anything except pattern. To match any string that does not end in .c, .Z, or .o:
or any string that does not contain digits:

4.6 Disabling File Name Substitution

File name substitution can be disabled by setting the noglob option using the set command:
        $ set —o noglob
        $ set —f

The -o noglob and -f options
for the set command are the same. Once file name substitution is
disabled, pattern-matching characters like *, ?, and ] lose their
special meaning:
        $ ls a*
        a* not found
        $ ls b?
        b? not found
Within [...] patterns, a / character is used to remove the meaning of the special pattern-matching characters. This means that the [/*/?]* pattern would match file names beginning with * or ?.

5 Command Substitution

substitution is a feature that allows output to be expanded from a
command. It can be used to assign the output of a command to a
variable, or to imbed the output of a command within another command.
The format for command substitution is:
where command is executed and the output is substituted for the entire $(command) construct.
For example, to print the current date in a friendly format:
        $ echo The date is $(date)
        The date is Fri Jul 27 10:41:21 PST 1996

5.1 Bourne Shell Compatibility

For compatibility with the Bourne shell, the following format for command substitution can also be used:
        `command `
Using `. . .` command substitution, we could get the names of the files in the current directory like this:
        $ echo `ls` are in this directory
        NEWS asp bin pc are this directory

5.2 Directing File Input

There is also a special form of the $(...) command that is used to substitute the contents of a file. The format for file input substitution is:
This is equivalent to $(cat file) or `cat file`, except that it is faster, because an extra process does not have to be created to execute the cat command.

5.3 Arithmetic Operations

Another form of the $(...) command is used to substitute the output of
arithmetic expressions. The value of an arithmetic expression is
returned when enclosed in double parentheses and preceded with a dollar
Here are a few examples.
        $ echo $((3+5))


        $ echo $((8192*16384%23))


5.4 Tilde Substitution

Tilde substitution is used to substitute the pathname of a user's home
directory for ~user. Words in the command line that start with the
tilde character cause the Korn shell to check the rest of the word up
to a slash. If the tilde character is found alone or is only followed
by a slash, it is replaced with the value of the HOME variable.

Korn Shell(K Shell) Notes (I)

Korn Shell Notes

1 Useful Cmds

wc - display a count of lines, words and characters in a file.
    It can be used to count the numbers together with other commands, such as ls, who and so on.

cut - cut out selected fields of each line of a file.
    The name of each unique user that is logged on is displayed using this command:
        $ who | cut —f1 —d' ' | sort —u



print is a Korn shell specialized command which is similar to echo.

nl - line numbering filter.

2 Conditional Execution

You can implement a simple if command by using the && and || operators together like this:
            command1 && command2 || command3
If command1 returns true, then command2 is executed, which causes
command3 to not be executed. If command1 does not return true, then
command2 is not executed, which causes command3 to be executed.

3 Grouping Commands

Commands enclosed in {} are executed in current shell. If

        $ echo "This is file temp:" ; cat temp | nl
        This is file temp:
        1 The rain in Spain
        2 falls mainly on the plain
then by using {}s, the output will be:
        $ { echo "This is file temp:"; cat temp ; } | nl
        1 This is file temp:
        2 The rain in Spain
        3 falls mainly on the plain
There must be whitespace after the opening {, and commands within the {}'s must be terminated with a semi-colon.

enclosed in () are executed in a subshell. Subshells are generated
whenever you enclose commands in ()'s, perform command substitution,
for background processes, and for coprocesses.A subshell is a separate
copy of the parent shell, so variables, functions, and aliases from the
parent shell are available to the subshell. However, subshells cannot
change the value of parent shell variables, functions, or aliases.

4 Redirecting Standard Output

By using the > symbol, the standard output of a command can be redirected to a file, instead of your terminal.

You can also use the > command to create an empty file:
    $ > tmp
    $ ls —s tmp
    0 tmp
This is equivalent to touch tmp.

Standard output can be appended to a file by using the >> redirect operator.

Standard output is closed with the >&- redirect operator:
    $ echo "This is going nowhere" >&-







Tcl/Tk Notes (3)

Part III Tcl Data Structures

1 More about Variables

  • The set command

        The set
command is used to define variables of any type. In addition, the set
command will return the value  of a variable if it is only passed a
single argument. It treats that argument as a variable name and returns
the current value of the variable.

    In the last command, $name gets substituted with var. Then the set command returns the value of var, which is the value of var. Another way to achieve a level of indirection like this is with nested set commands. The last set command above can be written as follows:
        set [set name]
        => the value of var

  • The unset command 

    You can delete a variable with the unset command:
        unset varName varName2 ...

  • Using info to find out about variables

    The existence of a variable can be tested with the info exists command.
        if ![info exists foobar]{
            set foobar 0
        } else {
            incr foobar }

2 Tcl Lists

    The Tcl list has the same structure as a Tcl command. That is, a
list is simply a string with list elements separated by white
space.Braces or quotes can be used to group words with whitespace into
a single list element.

3 Constructing Lists: list, lappend and concat

    The list
command constructs a list out of its arguments such that there is one
list element for each argument. if any of the arguments contain special
characters, the list command adds some quoting to ensure they are
parsed as a single element of the resulting list.

e.g. Constructing a list with the list command
        set x {1 2}
        => 1 2
        set x
        => 1 2
        list $x /$ foo
        => {1 2} {$} foo
[Note]: The braces used to group the list value into one argument to the set command are not part of the list value.

    The lappend command is used to append elements to the end of a list. You can call lappend with the name of an undefined variable and the variable will be created.
            lappend new 1 2
            => 1 2
            lappend new 3 "4 5"
            => 1 2 3 {4 5}
            set new
            => 1 2 3 {4 5}

    The concat
command is useful for splicing together lists. It works by
concatenating its arguments together, separating them with spaces. This
multiple lists into one where the top-level list elements in each input
list are also top-level list elements in the resulting list.
e.g. Using concat to splice together lists.
            concat 1 {2 3} {4 5 6}
            => 1 2 3 4 5 6
    It turns out that double quotes behave much like the concat command.
e.g. Double quotes compared to the list command.
            set x {1 2}
            => 1 2
            set y "$x 3"
            => 1 2 3
            set y [concat $x 3]
            => 1 2 3
            set z [list $x 3]
            =>{1 2} 3
    The basic rule is that list and lappend preserve preserve list structure, while concat(or double-quotes)eliminate one level of list structure.

4 Getting List Elements: llength, lindex, and lrange

    The llength command returns the number of elements in a list.
    The lindex command returns a particular element of a list. It takes an index. List indices count from zero. The keyword end means the last element, and it can be used with lindex, linsert, lrange and lreplace.
            lindex {1 2 3} 0
            => 1
lindex {1 2 3} 2
            => 3

    The lrange command returns a range of list elements. It takes a list and two indices as arguments.
            lrange {1 2 3 {4 5}} 2 end
            => 3 {4 5}

5 Modifying Lists: linsert and lreplace

    The linsert
command inserts elements into a list value at a specified index. If the
index is 0 or less, then elements are added to the front. If the index
is equal to or greater than the length of the list, then the elements
are appended to the end. Otherwise, the elements are inserted before
the element that is currentl as position index.
is used to replace a range of list elements with new elements. If you
don't specify any new elements, you effectively delete elements from a
            linsert {1 2} 0 new stuff
            => new stuff 1 2
            set x [list a {b c} e d]
            => a {b c} e d
            lreplace $x 1 2 B C
            => a B C d
            lreplace $x 0 0
            => {b c} e d

6 Searching Lists: lsearch

    lsearch returns the index of a value in the list, or -1 if it is not present. lsearch supports pattern matching in its search. Glob-style pattern matching is default, and this canbe disabled with the -exact flag.
    The example below uses lreplace to delete elements by not specifying any replacement list elements.
        proc delete {list value} {
            set ix [lsearch -exact $list $value]
            if {$ix>=0} {
                return [lreplace $list $ix $ix]
            } else {
                return $list

7 Sorting List: lsort

    The three basic types of sorts are specified with the -ascii, -integer, or -real options. The -increasing or -decreasing option indicate the sirting order. The default option set is -ascii -increasing.

8 The split And join Commands

    The split command
takes a string and turns it into a list by breaking it at specified
characters. Stray double-quotes or curly braces in the input can result
in invalid list structures and errors in your script. However, the
split command provides a robust way to turn input lines into proper Tcl

default split character is white space. If there are multiple separator
characters in a row, these result in empty list elements- the
separators are not collapsed. The following command splits on commas,
periods, spaces and tabs:

    The join command
is the inverse of split. It takes a list value and reformats it with
specified characters separating the list elements. In doing so, it will
remove any curly braces from the string representation of the list that
are used to group the top-level elements.

9 Arrays

    The index of an array is delimited by parentheses. The
index can have any string value, and it canbe the result of variable or
command substitution.
e.g.        set arra(index) value
    The value of an array element is obtained with $ substitution:
e.g.        set foo $arr(index)

you have complex indices, use a comma to separate different parts of
the index. Avoid putting a pace after the comma. It is legal, but a
space in an index value will cause problems because parenthesis are not
used as a grouping mechanism. The space in the index needs to be quoted
with a backslash, or hte whole variable reference needs to be grouped:
e.g.        set {arr(I'm asking for trouble)} {I told you so.}
the array index is stored in a variable, then there is no problem with
spaces in the variable's value. The following works fine:
            set index {
I'm asking for trouble}
            set arr($index) {
I told you so.}
name of the array can be the result of a substitution. If the name of
the array is stored in another variable, then you must use set as shown
in the last command below to reference the array elements.

10 The Array Command

    The array names command is perhaps the most useful because it allows easy iteration through an array with a foreach loop:
            foreach index [array names arr] {command body}
    The order of the names returned by array names is
arbitrary. It is essentially determined by the hash table
implementation of the array.
    The array get and array set operations are used to convert between an array and a list. The list returned by array get
has an even number of elements.The first element is an index, and the
next is the corresponding array value. The ordering of the indexes is
arbitrary. The list argument to array set must have the same structure.

11 Environment Variables

    In UNIX, the process environment variables are available through the global array env.
The name of the environment variable is the index,e.g. env(PATH), and
the array element contains the current value of the environment

12 Tracing Variable Values

    The trace command lets you register a command to be called whenever a variable is accessed, modified or unset. The form is:
        trace variable name ops command
    The name is a Tcl variable name, which can be a simple
variable, an array or a element.If a whole array is traced, then the
trace is invoked when any element is used according to ops. The ops
argument is one or more of the letters: r for read traces, w for write
traces, and u for unset traces. The command is executed when one of
these events occurs. It is invoked as:
        command name1 name2 op

    Information about traces on a varible is returned with the vinfo option.
        trace vinfo dynamic
        => {r FixDynamic}
    A trace is deleted with the vdelete trace option, which has the same form as the varible option.

Tcl/Tk Notes (1)

Tcl/Tk Notes

Part I TCL Overview

1 Everything Is a String

    In Tcl, evrything is a string, and you have to explicitly ask for evaluation of variables and nested commands.

2 Substitution

  • Variable
    The use of dollar sign($) is one kind of substitution. Variables can be assigned values by set command.

  • Command Substitution
    A nested command is delimited by square brackets, [ and ]. The Tcl
takes everything between the brackets and evaluates it as a command. It
Reqrites the outer command by replacing the square brackets and
everything between them with the result of nested command.

  • Math Expression
    The expr command is used to evaluate math expressions. The Tcl interpreter treats expr just like any other command, and it leaves the expression parsing up to the expr implementation.

  • Backslash Substitution

    Backslash(/) is used to quote characters that have special meaning to the interpreter.
    You can also specify characters that are hard to type directly by giving their octal or hexadecimal value.
 Another common use of backslashes is to continue long commands on
multiple lines. A backslash as the last character in a line is
converted into a space.

3 Double Quotes vs. Curly Braces

Double quotes, like braces, are used to group words together. The
difference between double quotes and curly braces is that quotes allow
substitutions to occur in the group, while curly braces prevent

In practice, grouping with curly braces is used when substitutions on
the argument need to be delayed until a later time( or never done at
all). Examples include contrl flow statements and procedure
declararions. Double quotes are usefulin simple cases like the puts command.

    Another common use of quotes is with the format command
that is similar to C printf function. The only way to effectively group
special characters in format command into a single argument is with
    e.g. puts [format "Item: %s/t%5.3f" $name $value]

4 Procedures

    Tcl uses the proc command to define procedures. The syntax is :
        proc name arglist body
    The return
command in Tcl procedure is optional because the interpreter will
return the value of the last command in the body as the value of the

5 A While Loop Example

    The loop around boolean expression $i<=10
is crucial, because it delays substitution until while command
implementation tests the expression. The following expression is an
infinite loop:
        set i; while $i<=10 {incr i}
    The Tcl interpreter will substitute for $i before while is called, so while gets a constant expression 1<=10
that will always be ture.You can avoid this kind of errors by adopting
a consistent coding style that always groups expressions and command
bodies with curly braces.
    The command in the example uses set with a single argument. When used in this way the set command returns the current value of the named variable.

6 Grouping And Command Substitution

decisions are made before substitutions are performed. This means that
the values of variables or command results do not affect grouping.
single round if substitutions is performed before command invocation.
That is, the result of a substitution is not interpreted a second time.
This rule is important if you have a variable value or a command result
that contains special characters such as spaces, dollar-signs, square
brackets or braces. Because only a single round of substitution is
done, you don't have to worry about special characters in values
causing extra substitutions.


uses # for comments. Unlike many languages, the # character must occur
at the begining of a command. An easy trick to append a comment to the
end of a command is to proceed the # with a semicolon in order to
terminate the previous command.
    A backslash(/)
continues a comment line onto the next line of the script. In addition,
a semi-colon inside a comment is not significant. only a newline
terminates comments.

8 Reference

  • backslash Sequences

  • Arithmetic Operators
  • Built-in Math Function
  • Core Tcl Commands

  • Predefined Variables