Next Previous Contents

7. How can I get bash to do certain common things?

7.1 How can I get bash to read and display eight-bit characters?

This is a process requiring several steps.

First, you must ensure that the `physical' data path is a full eight bits. For xterms, for example, the `vt100' resources `eightBitInput' and `eightBitOutput' should be set to `true'.

Once you have set up an eight-bit path, you must tell the kernel and tty driver to leave the eighth bit of characters alone when processing keyboard input. Use `stty' to do this:


        stty cs8 -istrip -parenb

For old BSD-style systems, you can use


        stty pass8

You may also need


        stty even odd

Finally, you need to tell readline that you will be inputting and displaying eight-bit characters. You use readline variables to do this. These variables can be set in your .inputrc or using the bash `bind' builtin. Here's an example using `bind':


        bash$ bind 'set convert-meta off'
        bash$ bind 'set meta-flag on'
        bash$ bind 'set output-meta on'

The `set' commands between the single quotes may also be placed in  /.inputrc.

7.2 How do I write a function `x' to replace builtin command `x', but

still invoke the command from within the function?

This is why the `command' and `builtin' builtins exist. The `command' builtin executes the command supplied as its first argument, skipping over any function defined with that name. The `builtin' builtin executes the builtin command given as its first argument directly.

For example, to write a function to replace `cd' that writes the hostname and current directory to an xterm title bar, use something like the following:


        cd()
        {
                builtin cd "$@" && xtitle "$HOST: $PWD"
        }

This could also be written using `command' instead of `builtin'; the version above is marginally more efficient.

7.3 How can I find the value of a shell variable whose name is the value

of another shell variable?

Versions of Bash newer than Bash-2.0 support this directly. You can use


        ${!var}

For example, the following sequence of commands will echo `z':


        var1=var2
        var2=z
        echo ${!var1}

For sh compatibility, use the `eval' builtin. The important thing to remember is that `eval' expands the arguments you give it again, so you need to quote the parts of the arguments that you want `eval' to act on.

For example, this expression prints the value of the last positional parameter:


        eval echo \"\$\{$#\}\"

The expansion of the quoted portions of this expression will be deferred until `eval' runs, while the `$#' will be expanded before `eval' is executed. In versions of bash later than bash-2.0,


        echo ${!#}

does the same thing.

7.4 How can I make the bash `time' reserved word print timing output that

looks like the output from my system's /usr/bin/time?

The bash command timing code looks for a variable `TIMEFORMAT' and uses its value as a format string to decide how to display the timing statistics.

The value of TIMEFORMAT is a string with `%' escapes expanded in a fashion similar in spirit to printf(3). The manual page explains the meanings of the escape sequences in the format string.

If TIMEFORMAT is not set, bash acts as if the following assignment had been performed:


        TIMEFORMAT=$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'

The POSIX.2 default time format (used by `time -p command') is


        TIMEFORMAT=$'real %2R\nuser %2U\nsys %2S'

The BSD /usr/bin/time format can be emulated with:


        TIMEFORMAT=$'\t%1R real\t%1U user\t%1S sys'

The System V /usr/bin/time format can be emulated with:


        TIMEFORMAT=$'\nreal\t%1R\nuser\t%1U\nsys\t%1S'

The ksh format can be emulated with:


        TIMEFORMAT=$'\nreal\t%2lR\nuser\t%2lU\nsys\t%2lS'

7.5 How do I get the current directory into my prompt?

Bash provides a number of backslash-escape sequences which are expanded when the prompt string (PS1 or PS2) is displayed. The full list is in the manual page.

The \w expansion gives the full pathname of the current directory, with a tilde (` ') substituted for the current value of $HOME. The \W expansion gives the basename of the current directory. To put the full pathname of the current directory into the path without any tilde subsitution, use $PWD. Here are some examples:


        PS1='\w$ '      # current directory with tilde
        PS1='\W$ '      # basename of current directory
        PS1='$PWD$ '    # full pathname of current directory

The single quotes are important in the final example to prevent $PWD from being expanded when the assignment to PS1 is performed.

7.6 How can I rename "*.foo" to "*.bar"?

Use the pattern removal functionality described in D3. The following `for' loop will do the trick:


        for f in *.foo; do
                mv $f ${f%foo}bar
        done

7.7 How can I translate a filename from uppercase to lowercase?

The script examples/functions/lowercase, originally written by John DuBois, will do the trick. The converse is left as an exercise.

7.8 How can I write a filename expansion (globbing) pattern that will match

all files in the current directory except "." and ".."?

You must have set the `extglob' shell option using `shopt -s extglob' to use this:


        echo .!(.|) *

A solution that works without extended globbing is given in the Unix Shell FAQ, posted periodically to comp.unix.shell.


Next Previous Contents