Next Previous Contents

4. Why does bash do some things differently than other Unix shells?

4.1 Why does bash run a different version of `command' than

`which command' says it will?

On many systems, `which' is actually a csh script that assumes you're running csh. In tcsh, `which' and its cousin `where' are builtins. On other Unix systems, `which' is a perl script that uses the PATH environment variable.

The csh script version reads the csh startup files from your home directory and uses those to determine which `command' will be invoked. Since bash doesn't use any of those startup files, there's a good chance that your bash environment differs from your csh environment. The bash `type' builtin does everything `which' does, and will report correct results for the running shell. If you're really wedded to the name `which', try adding the following function definition to your .bashrc:


        which()
        {
                builtin type "$@"
        }

If you're moving from tcsh and would like to bring `where' along as well, use this function:


        where()
        {
                builtin type -a "$@"
        }

4.2 Why doesn't bash treat brace expansions exactly like csh?

The only difference between bash and csh brace expansion is that bash requires a brace expression to contain at least one unquoted comma if it is to be expanded. Any brace-surrounded word not containing an unquoted comma is left unchanged by the brace expansion code. This affords the greatest degree of sh compatibility.

Bash, ksh, zsh, and pd-ksh all implement brace expansion this way.

4.3 Why doesn't bash have csh variable modifiers?

Posix has specified a more powerful, albeit somewhat more cryptic, mechanism cribbed from ksh, and bash implements it.

${parameter%word} Remove smallest suffix pattern. The WORD is expanded to produce a pattern. It then expands to the value of PARAMETER, with the smallest portion of the suffix matched by the pattern deleted.


        x=file.c
        echo ${x%.c}.o
        -->file.o

${parameter%%word}

Remove largest suffix pattern. The WORD is expanded to produce a pattern. It then expands to the value of PARAMETER, with the largest portion of the suffix matched by the pattern deleted.


        x=posix/src/std
        echo ${x%%/*}
        -->posix

${parameter#word} Remove smallest prefix pattern. The WORD is expanded to produce a pattern. It then expands to the value of PARAMETER, with the smallest portion of the prefix matched by the pattern deleted.


        x=$HOME/src/cmd
        echo ${x#$HOME}
        -->/src/cmd

${parameter##word} Remove largest prefix pattern. The WORD is expanded to produce a pattern. It then expands to the value of PARAMETER, with the largest portion of the prefix matched by the pattern deleted.


        x=/one/two/three
        echo ${x##*/}
        -->three

Given


        a=/a/b/c/d
        b=b.xxx
        csh                     bash            result
        ---                     ----            ------
        $a:h                    ${a%/*}            /a/b/c
        $a:t                    ${a##*/}           d
        $b:r                    ${b%.*}            b
        $b:e                    ${b##*.}           xxx

4.4 How can I make my csh aliases work when I convert to bash?

Bash uses a different syntax to support aliases than csh does. The details can be found in the documentation. We have provided a shell script which does most of the work of conversion for you; this script can be found in ./examples/misc/alias-conv.sh. Here is how you use it:

Start csh in the normal way for you. (e.g., `csh')

Pipe the output of `alias' through `alias-conv.sh', saving the results into `bash_aliases':


        alias | alias-conv.sh >bash_aliases

Edit `bash_aliases', carefully reading through any created functions. You will need to change the names of some csh specific variables to the bash equivalents. The script converts $cwd to $PWD, $term to $TERM, $home to $HOME, $user to $USER, and $prompt to $PS1. You may also have to add quotes to avoid unwanted expansion.

For example, the csh alias:


        alias cd 'cd \!*; echo $cwd'

is converted to the bash function:


        cd () { command cd "$@"; echo $PWD ; }

The only thing that needs to be done is to quote $PWD:


        cd () { command cd "$@"; echo "$PWD" ; }

Merge the edited file into your  /.bashrc.

There is an additional, more ambitious, script in examples/misc/cshtobash that attempts to convert your entire csh environment to its bash equivalent. This script can be run as simply `cshtobash' to convert your normal interactive environment, or as `cshtobash  /.login' to convert your login environment.

4.5 How can I pipe standard output and standard error from one command to

another, like csh does with `|&'?

Use


        command 2>&1 | command2

The key is to remember that piping is performed before redirection, so file descriptor 1 points to the pipe when it is duplicated onto file descriptor 2.

4.6 Now that I've converted from ksh to bash, are there equivalents to

ksh features like autoloaded functions and the `whence' command?

There are features in ksh-88 and ksh-93 that do not have direct bash equivalents. Most, however, can be emulated with very little trouble.

ksh-88 feature Bash equivalent -------------- --------------- compiled-in aliases set up aliases in .bashrc; some ksh aliases are bash builtins (hash, history, type) coprocesses named pipe pairs (one for read, one for write) typeset +f declare -F cd, print, whence function substitutes in examples/functions/kshenv autoloaded functions examples/functions/autoload is the same as typeset -fu read var?prompt read -p prompt var

ksh-93 feature Bash equivalent -------------- --------------- sleep, getconf Bash has loadable versions in examples/loadables ${.sh.version} $BASH_VERSION print -f printf hist alias fc=hist $HISTEDIT $FCEDIT


Next Previous Contents