34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<?xml version="1.0"?>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V5.0//EN" "http://www.oasis-open.org/docbook/xml/5.0b5/dtd/docbook.dtd" [
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <!ENTITY tag_bourneonly '<inlinemediaobject><imageobject><imagedata fileref="images/tag_bourne.png"></imagedata></imageobject><textobject><phrase>[Bourne]</phrase></textobject></inlinemediaobject> '>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <!ENTITY tag_kshonly '<inlinemediaobject><imageobject><imagedata fileref="images/tag_ksh.png"></imagedata></imageobject><textobject><phrase>[ksh]</phrase></textobject></inlinemediaobject> '>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <!ENTITY tag_ksh88only '<inlinemediaobject><imageobject><imagedata fileref="images/tag_ksh88.png"></imagedata></imageobject><textobject><phrase>[ksh88]</phrase></textobject></inlinemediaobject> '>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <!ENTITY tag_ksh93only '<inlinemediaobject><imageobject><imagedata fileref="images/tag_ksh93.png"></imagedata></imageobject><textobject><phrase>[ksh93]</phrase></textobject></inlinemediaobject> '>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <!ENTITY tag_performance '<inlinemediaobject><imageobject><imagedata fileref="images/tag_perf.png"></imagedata></imageobject><textobject><phrase>[perf]</phrase></textobject></inlinemediaobject> '>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <!ENTITY tag_i18n '<inlinemediaobject><imageobject><imagedata fileref="images/tag_i18n.png"></imagedata></imageobject><textobject><phrase>[i18n]</phrase></textobject></inlinemediaobject> '>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <!ENTITY tag_l10n '<inlinemediaobject><imageobject><imagedata fileref="images/tag_l10n.png"></imagedata></imageobject><textobject><phrase>[l10n]</phrase></textobject></inlinemediaobject> '>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz]>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<!--
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz CDDL HEADER START
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz The contents of this file are subject to the terms of the
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Common Development and Distribution License (the "License").
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz You may not use this file except in compliance with the License.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz or http://www.opensolaris.org/os/licensing.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz See the License for the specific language governing permissions
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz and limitations under the License.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz When distributing Covered Code, include this CDDL HEADER in each
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz file and include the License file at usr/src/OPENSOLARIS.LICENSE.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz If applicable, add the following below this CDDL HEADER, with the
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz fields enclosed by brackets "[]" replaced with your own identifying
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz information: Portions Copyright [yyyy] [name of copyright owner]
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz CDDL HEADER END
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz-->
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<!--
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Copyright 2009 Sun Microsystems, Inc. All rights reserved.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Use is subject to license terms.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz-->
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<!-- tag images were created like this:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz$ (text="perf" ;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz pbmtext -nomargins -lspace 0 -builtin fixed "${text}" |
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz pbmtopgm 1 1 |
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz pgmtoppm 1.0,1.0,1.0-0,0,0 /dev/stdin |
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz ppmtogif |
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz giftopnm |
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz pnmtopng >"tag_${text}.png")
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz-->
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<!-- compile with:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzxsltproc &minus;&minus;stringparam generate.section.toc.level 0 \
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz &minus;&minus;stringparam toc.max.depth 3 \
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz &minus;&minus;stringparam toc.section.depth 12 \
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz &minus;&minus;xinclude -o opensolaris_shell_styleguide.html /usr/share/sgml/docbook/docbook-xsl-stylesheets-1.69.1/html/docbook.xsl opensolaris_shell_styleguide.docbook
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz-->
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<article
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz xmlns:xlink="http://www.w3.org/1999/xlink"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz xmlns="http://docbook.org/ns/docbook"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz xml:lang="en">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <!-- xmlns:xi="http://www.w3.org/2001/XInclude" -->
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <info>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title><emphasis>[DRAFT]</emphasis> Bourne/Korn Shell Coding Conventions</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <!-- subtitle abuse -->
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <subtitle>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz This page is currently work-in-progress until it is approved by the OS/Net community. Please send any comments to
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <email>shell-discuss@opensolaris.org</email>.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </subtitle>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <authorgroup>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<!--
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <author><personname>David G. Korn</personname><email>dgk@research.att.com</email></author>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <author><personname>Roland Mainz</personname><email>roland.mainz@nrubsig.org</email></author>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <author><personname>Mike Shapiro</personname><email>mike.shapiro@sun.com</email></author>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz-->
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <author><orgname>OpenSolaris.org</orgname></author>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </authorgroup>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </info>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<section xml:id="intro">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Intro</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>This document describes the shell coding style used for all the SMF script changes integrated into (Open)Solaris.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>All new SMF shell code should conform to this coding standard, which is intended to match our existing C coding standard.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>When in doubt, think "what would be the C-Style equivalent ?" and "What does the POSIX (shell) standard say ?"</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</section><!-- end of intro -->
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<section xml:id="rules">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Rules</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="general">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>General</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="basic_format">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Basic Format</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Similar to <literal>cstyle</literal>, the basic format is that all
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz lines are indented by TABs or eight spaces, and continuation lines (which
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz in the shell end with "\") are indented by an equivalent number of TABs
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz and then an additional four spaces, e.g.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzcp foo bar
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzcp some_realllllllllllllllly_realllllllllllllly_long_path \
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz to_another_really_long_path
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>The encoding used for the shell scripts is either <literal>ASCII</literal>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz or <literal>UTF-8</literal>, alternative encodings are only allowed when the
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz application requires this.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="commenting">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Commenting</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Shell comments are preceded by the '<literal>#</literal>' character. Place
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz single-line comments in the right-hand margin. Use an extra '<literal>#</literal>'
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz above and below the comment in the case of multi-line comments:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzcp foo bar # Copy foo to bar
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz#
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# Modify the permissions on bar. We need to set them to root/sys
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# in order to match the package prototype.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz#
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzchown root bar
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzchgrp sys bar
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="interpreter_magic">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Interpreter magic</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>The proper interpreter magic for your shell script should be one of these:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz#!/bin/sh Standard Bourne shell script
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz#!/bin/ksh -p Standard Korn shell 88 script. You should always write ksh
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz scripts with -p so that ${ENV} (if set by the user) is not
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz sourced into your script by the shell.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz#!/bin/ksh93 Standard Korn shell 93 script (-p is not needed since ${ENV} is
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz only used for interactive shell sessions).
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="harden_your_script_against_unexpected_input">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Harden the script against unexpected (user) input</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Harden your script against unexpected (user) input, including
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz command line options, filenames with blanks (or other special
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz characters) in the name, or file input</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_builtin_commands">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly;&tag_performance;Use builtin commands if the shell provides them</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Use builtin commands if the shell provides them. For example ksh93s+
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (ksh93, version 's+') delivered with Solaris (as defined by PSARC 2006/550)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz supports the following builtins:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <simplelist type="inline">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>basename</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>cat</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>chgrp</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>chmod</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>chown</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>cmp</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>comm</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>cp</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>cut</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>date</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>dirname</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>expr</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>fds</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>fmt</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>fold</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>getconf</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>head</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>id</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>join</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>ln</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>logname</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>mkdir</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>mkfifo</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>mv</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>paste</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>pathchk</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>rev</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>rm</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>rmdir</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>stty</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>tail</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>tee</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>tty</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>uname</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>uniq</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>wc</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>sync</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </simplelist>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Those builtins can be enabled via <literal>$ builtin name_of_builtin #</literal> in shell
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz scripts (note that ksh93 builtins implement exact POSIX behaviour - some
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz commands in Solaris <filename>/usr/bin/</filename> directory implement pre-POSIX behaviour.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Add <literal>/usr/xpg6/bin/:/usr/xpg4/bin</literal> before
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <filename>/usr/bin/</filename> in <envar>${PATH}</envar> to test whether your script works with
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz the XPG6/POSIX versions)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_blocks_not_subshells">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_performance;Use blocks and not subshells if possible</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use blocks and not subshells if possible, e.g. use
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>$ { print "foo" ; print "bar" ; }</literal> instead of
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>$ (print "foo" ; print "bar") #</literal> - blocks are
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz faster since they do not require to save the subshell context (ksh93) or
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz trigger a shell child process (Bourne shell, bash, ksh88 etc.)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_long_options_for_set_builtin">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly; use long options for "<literal>set</literal>"</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>use long options for "<literal>set</literal>", for example instead of <literal>$ set -x #</literal>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz use <literal>$ set -o xtrace #</literal> to make the code more readable.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_posix_command_substitutions_syntax">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly; Use <literal>$(...)</literal> instead of <literal>`...`</literal> command substitutions</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use <literal>$(...)</literal> instead of <literal>`...`</literal> - <literal>`...`</literal>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz is an obsolete construct in ksh+POSIX sh scripts and <literal>$(...)</literal>.is a cleaner design,
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz requires no escaping rules, allows easy nesting etc.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <note><title>&tag_ksh93only; <literal>${ ...;}</literal>-style command substitutions</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>ksh93 has support for an alternative version of command substitutions with the
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz syntax <literal>${ ...;}</literal> which do not run in a subshell.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para></note>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="put_command_substitution_result_in_quotes">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly; Always put the result of a <literal>$(...)</literal> or
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>$( ...;)</literal> command substitution in quotes</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Always put the result of <literal>$( ... )</literal> or <literal>$( ...;)</literal> in
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz quotes (e.g. <literal>foo="$( ... )"</literal> or <literal>foo="$( ...;)"</literal>) unless
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz there is a very good reason for not doing it</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="always_set_path">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Scripts should always set their <envar>PATH</envar></title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Scripts should always set their <envar>PATH</envar> to make sure they do not use
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz alternative commands by accident (unless the value of <envar>PATH</envar> is well-known
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz and guaranteed to be set by the caller)</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="make_sure_commands_are_available">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Make sure that commands from other packages/applications are really installed on the machine</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Scripts should make sure that commands in optional packages are really
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz there, e.g. add a "precheck" block in scipts to avoid later failure when
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz doing the main job</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="check_usage_of_boolean_variables">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Check how boolean values are used/implemented in your application</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Check how boolean values are used in your application.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>For example:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzmybool=0
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# do something
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [ $mybool -eq 1 ] ; then do_something_1 ; fi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzcould be rewritten like this:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzmybool=false # (valid values are "true" or "false", pointing
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# to the builtin equivalents of /bin/true or /bin/false)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# do something
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif ${mybool} ; then do_something_1 ; fi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzor
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzinteger mybool=0 # values are 0 or 1
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# do something
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif (( mybool==1 )) ; then do_something_1 ; fi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="shell_uses_characters_not_bytes">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_i18n;The shell always operates on <emphasis>characters</emphasis> not bytes</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Shell scripts operate on characters and <emphasis>not</emphasis> bytes.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Some locales use multiple bytes (called "multibyte locales") to represent one character</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <note><para>ksh93 has support for binary variables which explicitly
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz operate on bytes, not characters. This is the <emphasis>only</emphasis> allowed
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz exception.</para></note>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="multibyte_locale_input">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_i18n;Multibyte locales and input</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Think about whether your application has to handle file names or
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz variables in multibyte locales and make sure all commands used in your
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz script can handle such characters (e.g. lots of commands in Solaris's
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <filename>/usr/bin/</filename> are <emphasis>not</emphasis> able to handle such values - either use ksh93
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz builtin constructs (which are guaranteed to be multibyte-aware) or
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz commands from <filename>/usr/xpg4/bin/</filename> and/or <filename>/usr/xpg6/bin</filename>)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_external_filters_only_for_large_datasets">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_performance;Only use external filters like <literal>grep</literal>/<literal>sed</literal>/<literal>awk</literal>/etc.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if you want to process lots of data with them</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Only use external filters like <literal>grep</literal>/<literal>sed</literal>/<literal>awk</literal>/etc.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if a significant amount of data is processed by the filter or if
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz benchmarking shows that the use of builtin commands is significantly slower
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (otherwise the time and resources needed to start the filter are
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz far greater then the amount of data being processed,
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz creating a performance problem).</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>For example:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [ "$(echo "$x" | egrep '.*foo.*')" != "" ] ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz do_something ;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzdone
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzcan be re-written using ksh93 builtin constructs, saving several
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<literal>|fork()|+|exec()|</literal>'s:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [[ "${x}" == ~(E).*foo.* ]] ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz do_something ;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzdone
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_dashdash_if_first_arg_is_variable">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>If the first operand of a command is a variable, use <literal>--</literal></title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>If the first operand of a command is a variable, use <literal>--</literal>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz for any command that accepts this as end of argument to
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz avoid problems if the variable expands to a value starting with <literal>-</literal>.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <note><para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz At least
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <simplelist type="inline">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>print</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>/usr/bin/fgrep</member><member>/usr/xpg4/bin/fgrep</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>/usr/bin/grep</member> <member>/usr/xpg4/bin/grep</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>/usr/bin/egrep</member><member>/usr/xpg4/bin/egrep</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </simplelist>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz support <literal>--</literal> as "end of arguments"-terminator.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para></note>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_export">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly;&tag_performance;Use <literal>$ export FOOBAR=val #</literal> instead of
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>$ FOOBAR=val ; export FOOBAR #</literal></title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use <literal>$ export FOOBAR=val # instead of $ FOOBAR=val ; export FOOBAR #</literal> -
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz this is much faster.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_subshell_around_set_dashdash_usage">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Use a subshell (e.g. <literal>$ ( mycmd ) #</literal>) around places which use
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>set -- $(mycmd)</literal> and/or <literal>shift</literal></title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use a subshell (e.g. <literal>$ ( mycmd ) #</literal>) around places which use
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>set -- $(mycmd)</literal> and/or <literal>shift</literal> unless the variable
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz affected is either a local one or if it's guaranteed that this variable will no longer be used
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (be careful for loadable functions, e.g. ksh/ksh93's <literal>autoload</literal> !!!!)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="be_careful_with_tabs_in_script_code">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Be careful with using TABS in script code, they are not portable
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz between editors or platforms</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Be careful with using TABS in script code, they are not portable
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz between editors or platforms.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>If you use ksh93 use <literal>$'\t'</literal> to include TABs in sources, not the TAB character itself.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="centralise_error_exit">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>If you have multiple points where your application exits with an error
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz message create a central function for this purpose</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>If you have multiple points where your application exits with an error
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz message create a central function for this, e.g.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [ -z "$tmpdir" ] ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz print -u2 "mktemp failed to produce output; aborting."
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz exit 1
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [ ! -d $tmpdir ] ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz print -u2 "mktemp failed to create a directory; aborting."
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz exit 1
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzshould be replaced with
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfunction fatal_error
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz{
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz print -u2 "${progname}: $*"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz exit 1
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz}
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# do something (and save ARGV[0] to variable "progname")
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [ -z "$tmpdir" ] ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz fatal_error "mktemp failed to produce output; aborting."
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [ ! -d "$tmpdir" ] ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz fatal_error "mktemp failed to create a directory; aborting."
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_set_o_nounset">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly; Think about using <literal>$ set -o nounset #</literal> by default</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Think about using <literal>$ set -o nounset #</literal> by default (or at least during the
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz script's development phase) to catch errors where variables are used
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz when they are not set (yet), e.g.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<screen>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz$ <userinput>(set -o nounset ; print ${foonotset})</userinput>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<computeroutput>/bin/ksh93: foonotset: parameter not set</computeroutput>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</screen>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="avoid_eval_builtin">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Avoid using <literal>eval</literal> unless absolutely necessary</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Avoid using <literal>eval</literal> unless absolutely necessary. Subtle things
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz can happen when a string is passed back through the shell
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz parser. You can use name references to avoid uses such as
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>eval $name="$value"</literal>.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_concatenation_operator">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_ksh93only;Use the string/array concatenation operator <literal>+=</literal></title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use <literal>+=</literal> instead of manually adding strings/array elements, e.g.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfoo=""
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfoo="${foo}a"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfoo="${foo}b"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfoo="${foo}c"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzshould be replaced with
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfoo=""
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfoo+="a"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfoo+="b"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfoo+="c"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_source_not_dot">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_ksh93only;Use <literal>source</literal> instead of '<literal>.</literal> '(dot)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz to include other shell script fragments</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use <literal>source</literal> instead of '<literal>.</literal>'
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (dot) to include other shell script fragments - the new form is much
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz more readable than the tiny dot and a failure can be caught within the script.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_builtin_localisation_support">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_ksh93only;&tag_performance;&tag_l10n;Use <literal>$"..."</literal> instead of
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>gettext ... "..."</literal> for strings that need to be localized for different locales</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use $"..." instead of <literal>gettext ... "..."</literal> for strings that need to be
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz localized for different locales. <literal>gettext</literal> will require a
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>fork()+exec()</literal> and
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz reads the whole catalog each time it's called, creating a huge overhead for localisation
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (and the <literal>$"..."</literal> is easier to use, e.g. you only have to put a
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>$</literal> in front of the catalog and the string will be localised).
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_set_o_noglob">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly;&tag_performance;Use <literal>set -o noglob</literal> if you do not need to expand files</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>If you don't expect to expand files, you can do set <literal>-f</literal>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (<literal>set -o noglob</literal>) as well. This way the need to use <literal>""</literal> is
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz greatly reduced.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_empty_ifs_to_handle_spaces">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_ksh93only;Use <literal>IFS=</literal> to avoid problems with spaces in filenames</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Unless you want to do word splitting, put <literal>IFS=</literal>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz at the beginning of a command. This way spaces in
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz file names won't be a problem. You can do
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>IFS='delims' read -r</literal> line
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz to override <envar>IFS</envar> just for the <literal>read</literal> command. However,
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz you can't do this for the <literal>set</literal> builtin.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="set_locale_when_comparing_against_localised_output">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Set the message locale if you process output of tools which may be localised</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Set the message locale (<envar>LC_MESSAGES</envar>) if you process output of tools which may be localised</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <example><title>Set <envar>LC_MESSAGES</envar> when testing for specific outout of the <filename>/usr/bin/file</filename> utility:</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# set french as default message locale
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzexport LC_MESSAGES=fr_FR.UTF-8
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz...
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# test whether the file "/tmp" has the filetype "directory" or not
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# we set LC_MESSAGES to "C" to ensure the returned message is in english
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [[ "$(LC_MESSAGES=C file /tmp)" = *directory ]] ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz print "is a directory"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <note><para>The environment variable <envar>LC_ALL</envar> always
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz overrides any other <envar>LC_*</envar> environment variables
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (and <envar>LANG</envar>, too),
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz including <envar>LC_MESSAGES</envar>.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if there is the chance that <envar>LC_ALL</envar> may be set
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz replace <envar>LC_MESSAGES</envar> with <envar>LC_ALL</envar>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz in the example above.</para></note>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </example>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="cleanup_after_yourself">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Cleanup after yourself.</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Cleanup after yourself. For example ksh/ksh93 have an <literal>EXIT</literal> trap which
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz is very useful for this.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <note><para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Note that the <literal>EXIT</literal> trap is executed for a subshell and each subshell
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz level can run it's own <literal>EXIT</literal> trap, for example
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<screen>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz$ <userinput>(trap "print bam" EXIT ; (trap "print snap" EXIT ; print "foo"))</userinput>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<computeroutput>foo
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzsnap
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzbam</computeroutput>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</screen>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para></note>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_proper_exit_code">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Use a proper <literal>exit</literal> code</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Explicitly set the exit code of a script, otherwise the exit code
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz from the last command executed will be used which may trigger problems
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if the value is unexpected.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="shell_lint">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_ksh93only;Use <literal>shcomp -n scriptname.sh /dev/null</literal> to check for common errors</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use <literal>shcomp -n scriptname.sh /dev/null</literal> to
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz check for common problems (such as insecure, depreciated or ambiguous constructs) in shell scripts.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section><!-- end of general -->
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="functions">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Functions</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_functions">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Use functions to break up your code</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use functions to break up your code into smaller, logical blocks.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="do_not_reserved_keywords_for_function_names">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Do not use function names which are reserved keywords in C/C++/JAVA or the POSIX shell standard</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Do not use function names which are reserved keywords (or function names) in C/C++/JAVA or the POSIX shell standard
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (to avoid confusion and/or future changes/updates to the shell language).
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_ksh_style_function_syntax">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly;&tag_performance;Use ksh-style <literal>function</literal></title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>It is <emphasis>highly</emphasis> recommended to use ksh style functions
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (<literal>function foo { ... }</literal>) instead
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz of Bourne-style functions (<literal>foo() { ... }</literal>) if possible
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (and local variables instead of spamming the global namespace).</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <warning><para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz The difference between old-style Bourne functions and ksh functions is one of the major differences
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz between ksh88 and ksh93 - ksh88 allowed variables to be local for Bourne-style functions while ksh93
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz conforms to the POSIX standard and will use a function-local scope for variables declared in
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Bourne-style functions.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Example (note that "<literal>integer</literal>" is an alias for "<literal>typeset -li</literal>"):
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# new style function with local variable
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz$ ksh93 -c 'integer x=2 ; function foo { integer x=5 ; } ; print "x=$x"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz; foo ; print "x=$x" ;'
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzx=2
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzx=2
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# old style function with an attempt to create a local variable
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz$ ksh93 -c 'integer x=2 ; foo() { integer x=5 ; } ; print "x=$x" ; foo ;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzprint "x=$x" ;'
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzx=2
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzx=5
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <uri xlink:href="http://www.opensolaris.org/os/project/ksh93-integration/docs/ksh93r/general/compatibility/">usr/src/lib/libshell/common/COMPATIBILITY</uri>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz says about this issue:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<blockquote><para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland MainzFunctions, defined with name() with ksh-93 are compatible with
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzthe POSIX standard, not with ksh-88. No local variables are
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzpermitted, and there is no separate scope. Functions defined
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzwith the function name syntax, maintain compatibility.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland MainzThis also affects function traces.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</para></blockquote>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz(this issue also affects <filename>/usr/xpg4/bin/sh</filename> in Solaris 10 because it is based on ksh88. This is a bug.).
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para></warning>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_proper_return_code">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Use a proper <literal>return</literal> code</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Explicitly set the return code of a function - otherwise the exit code
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz from the last command executed will be used which may trigger problems
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if the value is unexpected.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>The only allowed exception is if a function uses the shell's <literal>errexit</literal> mode to leave
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz a function, subshell or the script if a command returns a non-zero exit code.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_fpath_to_load_common_code">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly;Use <envar>FPATH</envar> to load common functions, not <literal>source</literal></title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Use the ksh <envar>FPATH</envar> (function path) feature to load functions which are shared between scripts
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz and not <literal>source</literal> - this allows to load such a function on demand and not all at once.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section><!-- end of functions -->
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="if_for_while">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title><literal>if</literal>, <literal>for</literal> and <literal>while</literal></title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="if_for_while_format">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Format</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>To match <literal>cstyle</literal>, the shell token equivalent to the <literal>C</literal>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz "<literal>{</literal>" should appear on the same line, separated by a
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz "<literal>;</literal>", as in:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [ "$x" = "hello" ] ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz echo $x
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [[ "$x" = "hello" ]] ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz print $x
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfor i in 1 2 3; do
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz echo $i
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzdone
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfor ((i=0 ; i &lt; 3 ; i++)); do
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz print $i
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzdone
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzwhile [ $# -gt 0 ]; do
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz echo $1
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz shift
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzdone
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzwhile (( $# &gt; 0 )); do
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz print $1
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz shift
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzdone
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="test_builtin">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title><literal>test</literal> Builtin</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>DO NOT use the test builtin. Sorry, executive decision.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>In our Bourne shell, the <literal>test</literal> built-in is the same as the "["
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz builtin (if you don't believe me, try "type test" or refer to <filename>usr/src/cmd/sh/msg.c</filename>).</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz So please do not write:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif test $# -gt 0 ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzinstead use:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [ $# -gt 0 ] ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_ksh_test_syntax">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly;&tag_performance;Use "<literal>[[ expr ]]</literal>" instead of "<literal>[ expr ]</literal>"</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use "<literal>[[ expr ]]</literal>" instead of "<literal>[ expr ]</literal>" if possible
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz since it avoids going through the whole pattern expansion/etc. machinery and
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz adds additional operators not available in the Bourne shell, such as short-circuit
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>&amp;&amp;</literal> and <literal>||</literal>.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_posix_arithmetic_expressions">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly; Use "<literal>(( ... ))</literal>" for arithmetic expressions</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use "<literal>(( ... ))</literal>" instead of "<literal>[ expr ]</literal>"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz or "<literal>[[ expr ]]</literal>" expressions.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Example: Replace
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzi=5
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# do something
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [ $i -gt 5 ] ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzwith
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzi=5
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# do something
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif (( i &gt; 5 )) ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="compare_exit_code_using_math">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly;&tag_performance;Compare exit code using arithmetic expressions expressions</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use POSIX arithmetic expressions to test for exit/return codes of commands and functions.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz For example turn
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [ $? -gt 0 ] ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzinto
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif (( $? &gt; 0 )) ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_builtin_commands_in_loops">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_bourneonly; Use builtin commands in conditions for <literal>while</literal> endless loops</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Make sure that your shell has a "<literal>true</literal>" builtin (like ksh93) when
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz executing endless loops like <literal>$ while true ; do do_something ; done #</literal> -
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz otherwise each loop cycle runs a <literal>|fork()|+|exec()|</literal>-cycle to run
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <filename>/bin/true</filename>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="single_line_if_statements">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Single-line if-statements</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>It is permissible to use <literal>&amp;&amp;</literal> and <literal>||</literal> to construct
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz shorthand for an "<literal>if</literal>" statement in the case where the if statement has a
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz single consequent line:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz[ $# -eq 0 ] &amp;&amp; exit 0
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzinstead of the longer:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [ $# -eq 0 ]; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz exit 0
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="exit_status_and_if_for_while">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Exit Status and <literal>if</literal>/<literal>while</literal> statements</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Recall that "<literal>if</literal>" and "<literal>while</literal>"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz operate on the exit status of the statement
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz to be executed. In the shell, zero (0) means true and non-zero means false.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz The exit status of the last command which was executed is available in the $?
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz variable. When using "<literal>if</literal>" and "<literal>while</literal>",
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz it is typically not necessary to use
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>$?</literal> explicitly, as in:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzgrep foo /etc/passwd &gt;/dev/null 2>&amp;1
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [ $? -eq 0 ]; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz echo "found"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland MainzInstead, you can more concisely write:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif grep foo /etc/passwd &gt;/dev/null 2>&amp;1; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz echo "found"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland MainzOr, when appropriate:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzgrep foo /etc/passwd &gt;/dev/null 2>&amp;1 &amp;&amp; echo "found"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section><!-- end of if/for/while -->
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="variables">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Variable types, naming and usage</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="names_should_be_lowercase">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Names of local, non-environment, non-constant variables should be lowercase</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Names of variables local to the current script which are not exported to the environment
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz should be lowercase while variable names which are exported to the
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz environment should be uppercase.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>The only exception are global constants (=global readonly variables,
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz e.g. <literal>$ float -r M_PI=3.14159265358979323846 #</literal> (taken from &lt;math.h&gt;))
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz which may be allowed to use uppercase names, too.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <warning><para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Uppercase variable names should be avoided because there is a good chance
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz of naming collisions with either special variable names used by the shell
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (e.g. <literal>PWD</literal>, <literal>SECONDS</literal> etc.).
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para></warning>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="do_not_reserved_keywords_for_variable_names">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Do not use variable names which are reserved keywords/variable names in C/C++/JAVA or the POSIX shell standard</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Do not use variable names which are reserved keywords in C/C++/JAVA or the POSIX shell standard
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (to avoid confusion and/or future changes/updates to the shell language).
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <note>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>The Korn Shell and the POSIX shell standard have many more
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz reserved variable names than the original Bourne shell. All
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz these reserved variable names are spelled uppercase.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </note>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_brackets_around_long_names">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Always use <literal>'{'</literal>+<literal>'}'</literal> when using variable
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz names longer than one character</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Always use <literal>'{'</literal>+<literal>'}'</literal> when using
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz variable names longer than one character unless a simple variable name is
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz followed by a blank, <literal>/</literal>, <literal>;</literal>, or <literal>$</literal>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz character (to avoid problems with array,
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz compound variables or accidental misinterpretation by users/shell)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzprint "$foo=info"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzshould be rewritten to
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzprint "${foo}=info"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="quote_variables_containing_filenames_or_userinput">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title><emphasis>Always</emphasis> put variables into quotes when handling filenames or user input</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para><emphasis>Always</emphasis> put variables into quotes when handling filenames or user input, even if
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz the values are hardcoded or the values appear to be fixed. Otherwise at
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz least two things may go wrong:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <itemizedlist>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <listitem><para>a malicious user may be able to exploit a script's inner working to
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz infect his/her own code</para></listitem>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <listitem><para>a script may (fatally) misbehave for unexpected input (e.g. file names
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz with blanks and/or special symbols which are interpreted by the shell)</para></listitem>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </itemizedlist>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <note><para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz As alternative a script may set <literal>IFS='' ; set -o noglob</literal> to turn off the
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz interpretation of any field seperators and the pattern globbing.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para></note>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_typed_variables">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly;&tag_performance;Use typed variables if possible.</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>For example the following is very
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz inefficient since it transforms the integer values to strings and back
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz several times:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainza=0
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzb=1
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzc=2
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# more code
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [ $a -lt 5 -o $b -gt c ] ; then do_something ; fi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland MainzThis could be rewritten using ksh constructs:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzinteger a=0
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzinteger b=1
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzinteger c=2
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# more code
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif (( a &lt; 5 || b &gt; c )) ; then do_something ; fi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="store_lists_in_arrays">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_ksh93only; Store lists in arrays or associative arrays</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Store lists in arrays or associative arrays - this is usually easier
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz to manage.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz For example:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzx="
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz/etc/foo
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz/etc/bar
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz/etc/baz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzecho $x
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzcan be replaced with
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainztypeset -a mylist
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzmylist[0]="/etc/foo"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzmylist[1]="/etc/bar"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzmylist[2]="/etc/baz"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzprint "${mylist[@]}"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzor (ksh93-style append entries to a normal (non-associative) array)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainztypeset -a mylist
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzmylist+=( "/etc/foo" )
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzmylist+=( "/etc/bar" )
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzmylist+=( "/etc/baz" )
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzprint "${mylist[@]}"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <note>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Difference between expanding arrays with mylist[@] and mylist[*] subscript operators</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Arrays may be expanded using two similar subscript operators, @ and *. These subscripts
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz differ only when the variable expansion appears within double quotes. If the variable expansion
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz is between double-quotes, "${mylist[*]}" expands to a single string with the value of each array
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz member separated by the first character of the <envar>IFS</envar> variable, and "${mylist[@]}"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz expands each element of name to a separate string.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <example><title>Difference between [@] and [*] when expanding arrays</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainztypeset -a mylist
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzmylist+=( "/etc/foo" )
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzmylist+=( "/etc/bar" )
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzmylist+=( "/etc/baz" )
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland MainzIFS=","
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzprintf "mylist[*]={ 0=|%s| 1=|%s| 2=|%s| 3=|%s| }\n" "${mylist[*]}"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzprintf "mylist[@]={ 0=|%s| 1=|%s| 2=|%s| 3=|%s| }\n" "${mylist[@]}"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<para>will print:</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<screen>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<computeroutput>mylist[*]={ 0=|/etc/foo,/etc/bar,/etc/baz| 1=|| 2=|| 3=|| }
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzmylist[@]={ 0=|/etc/foo| 1=|/etc/bar| 2=|/etc/baz| 3=|| }
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</computeroutput>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</screen>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </example>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </note>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_compound_variables_or_lists_for_grouping">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_ksh93only; Use compound variables or associative arrays to group similar variables together</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use compound variables or associative arrays to group similar variables together.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz For example:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzbox_width=56
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzbox_height=10
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzbox_depth=19
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzecho "${box_width} ${box_height} ${box_depth}"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzcould be rewritten to ("associative array"-style)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainztypeset -A -E box=( [width]=56 [height]=10 [depth]=19 )
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzprint -- "${box[width]} ${box[height]} ${box[depth]}"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzor ("compound variable"-style
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzbox=(
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz float width=56
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz float height=10
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz float depth=19
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz )
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzprint -- "${box.width} ${box.height} ${box.depth}"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section><!-- end of variables -->
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="io">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>I/O</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="avoid_echo">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Avoid using the "<literal>echo</literal>" command for output</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>The behaviour of "<literal>echo</literal>" is not portable
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (e.g. System V, BSD, UCB and ksh93/bash shell builtin versions all
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz slightly differ in functionality) and should be avoided if possible.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz POSIX defines the "<literal>printf</literal>" command as replacement
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz which provides more flexible and portable behaviour.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <note>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly;Use "<literal>print</literal>" and not "<literal>echo</literal>" in Korn Shell scripts</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Korn shell scripts should prefer the "<literal>print</literal>"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz builtin which was introduced as replacement for "<literal>echo</literal>".</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <caution>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use <literal>$ print -- ${varname}" #</literal> when there is the slightest chance that the
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz variable "<literal>varname</literal>" may contain symbols like "-". Or better use "<literal>printf</literal>"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz instead, for example
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzinteger fx
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# do something
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzprint $fx
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzmay fail if "f" contains a negative value. A better way may be to use
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzinteger fx
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# do something
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzprintf "%d\n" fx
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </caution>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </note>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_redirect_not_exec_to_open_files">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_ksh93only;Use <literal>redirect</literal> and not <literal>exec</literal> to open files</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use <literal>redirect</literal> and not <literal>exec</literal> to open files - <literal>exec</literal>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz will terminate the current function or script if an error occurs while <literal>redirect</literal>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz just returns a non-zero exit code which can be caught.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<para>Example:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif redirect 5&lt;/etc/profile ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz print "file open ok"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz head &lt;&amp;5
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzelse
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz print "could not open file"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="group_identical_redirections_together">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_performance;Avoid redirections per command when the output goes into the same file,
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz e.g. <literal>$ echo "foo" &gt;xxx ; echo "bar" &gt;&gt;xxx ; echo "baz" &gt;&gt;xxx #</literal></title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Each of the redirections above trigger an
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>|open()|,|write()|,|close()|</literal>-sequence. It is much
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz more efficient (and faster) to group the rediction into a block,
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz e.g. <literal>{ echo "foo" ; echo "bar" ; echo "baz" } &gt;xxx #</literal></para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="avoid_using_temporary_files">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_performance;Avoid the creation of temporary files and store the values in variables instead</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Avoid the creation of temporary files and store the values in variables instead if possible</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Example:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzls -1 &gt;xxx
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfor i in $(cat xxx) ; do
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz do_something ;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzdone
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzcan be replaced with
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzx="$(ls -1)"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfor i in ${x} ; do
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz do_something ;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzdone
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <note><para>ksh93 supports binary variables (e.g. <literal>typeset -b varname</literal>) which can hold any value.</para></note>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="create_subdirs_for_multiple_temporary_files">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>If you create more than one temporary file create an unique subdir</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>If you create more than one temporary file create an unique subdir for
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz these files and make sure the dir is writable. Make sure you cleanup
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz after yourself (unless you are debugging).
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_dynamic_file_descriptors">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_ksh93only;Use {n}&lt;file instead of fixed file descriptor numbers</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>When opening a file use {n}&lt;file, where <envar>n</envar> is an
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz integer variable rather than specifying a fixed descriptor number.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>This is highly recommended in functions to avoid that fixed file
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz descriptor numbers interfere with the calling script.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<example><title>Open a network connection and store the file descriptor number in a variable</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfunction cat_http
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz{
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz integer netfd
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz...
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz # open TCP channel
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz redirect {netfd}&lt;&gt;"/dev/tcp/${host}/${port}"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz # send HTTP request
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz request="GET /${path} HTTP/1.1\n"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz request+="Host: ${host}\n"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz request+="User-Agent: demo code/ksh93 (2007-08-30; $(uname -s -r -p))\n"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz request+="Connection: close\n"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz print "${request}\n" &gt;&amp;${netfd}
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz # collect response and send it to stdout
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz cat &lt;&amp;${netfd}
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz # close connection
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz exec {netfd}&lt;&amp;-
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz...
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz}
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</example>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_inline_here_documents">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_ksh93only;&tag_performance;Use inline here documents
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz instead of <literal>echo "$x" | command</literal></title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use inline here documents, for example
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzcommand &lt;&lt;&lt; $x
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz rather than
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzprint -r -- "$x" | command
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_read_r">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_ksh93only;Use the <literal>-r</literal> option of <literal>read</literal> to read a line</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use the <literal>-r</literal> option of <literal>read</literal> to read a line.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz You never know when a line will end in <literal>\</literal> and without a
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>-r</literal> multiple
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz lines can be read.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="print_compound_variables_using_print_C">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_ksh93only;Print compound variables using <literal>print -C varname</literal> or <literal>print -v varname</literal></title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Print compound variables using <literal>print -C varname</literal> or
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>print -v varname</literal> to make sure that non-printable characters
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz are correctly encoded.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<example><title>Print compound variable with non-printable characters</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzcompound x=(
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz a=5
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz b="hello"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz c=(
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz d=9
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz e="$(printf "1\v3")" <co xml:id="co.vertical_tab1" />
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz )
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzprint -v x
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<para>will print:</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<screen>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<computeroutput>(
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz a=5
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz b=hello
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz c=(
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz d=9
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz e=$'1\0133' <co xml:id="co.vertical_tab2" />
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz )
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz)</computeroutput>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</screen>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<calloutlist>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <callout arearefs="co.vertical_tab1 co.vertical_tab2">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>vertical tab, <literal>\v</literal>, octal=<literal>\013</literal>.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </callout>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</calloutlist>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</example>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="command_name_before_redirections">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Put the command name and arguments before redirections</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Put the command name and arguments before redirections.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz You can legally do <literal>$ &gt; file date</literal> instead of <literal>date &gt; file</literal>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz but don't do it.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="enable_gmacs_editor_mode_for_user_prompts">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_ksh93only;Enable the <literal>gmacs</literal> editor
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz mode when reading user input using the <literal>read</literal> builtin</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Enable the <literal>gmacs</literal>editor mode before reading user
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz input using the <literal>read</literal> builtin to enable the use of
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz cursor+backspace+delete keys in the edit line</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<example><title>Prompt user for a string with gmacs editor mode enabled</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzset -o gmacs <co xml:id="co.enable_gmacs" />
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainztypeset inputstring="default value"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz...
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzread -v<co xml:id="co.read_v" /> inputstring<co xml:id="co.readvar" />?"Please enter a string: "<co xml:id="co.prompt" />
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz...
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzprintf "The user entered the following string: '%s'\n" "${inputstring}"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz...
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<calloutlist>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <callout arearefs="co.enable_gmacs">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Enable gmacs editor mode.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </callout>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <callout arearefs="co.read_v">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>The value of the variable is displayed and used as a default value.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </callout>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <callout arearefs="co.readvar">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Variable used to store the result.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </callout>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <callout arearefs="co.prompt">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Prompt string which is displayed in stderr.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </callout>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</calloutlist>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</example>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section><!-- end of I/O -->
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="math">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Math</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_builtin_arithmetic_expressions">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly;&tag_performance;Use builtin arithmetic expressions instead of external applications</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use builtin (POSIX shell) arithmetic expressions instead of
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <filename>expr</filename>,
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <filename>bc</filename>,
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <filename>dc</filename>,
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <filename>awk</filename>,
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <filename>nawk</filename> or
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <filename>perl</filename>.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <note>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>ksh93 supports C99-like floating-point arithmetic including special values
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz such as
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <simplelist type="inline">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>+Inf</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>-Inf</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>+NaN</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <member>-NaN</member>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </simplelist>.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </note>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_floating_point_arithmetic_expressions">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_ksh93only; Use floating-point arithmetic expressions if
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz calculations may trigger a division by zero or other exceptions</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use floating-point arithmetic expressions if calculations may
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz trigger a division by zero or other exceptions - floating point arithmetic expressions in
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz ksh93 support special values such as <literal>+Inf</literal>/<literal>-Inf</literal> and
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>+NaN</literal>/<literal>-NaN</literal> which can greatly simplify testing for
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz error conditions, e.g. instead of a <literal>trap</literal> or explicit
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <literal>if ... then... else</literal> checks for every sub-expression
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz you can check the results for such special values.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Example:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<screen>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz$ <userinput>ksh93 -c 'integer i=0 j=5 ; print -- "x=$((j/i)) "'</userinput>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<computeroutput>ksh93: line 1: j/i: divide by zero</computeroutput>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz$ <userinput>ksh93 -c 'float i=0 j=-5 ; print -- "x=$((j/i)) "'</userinput>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<computeroutput>x=-Inf</computeroutput>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</screen>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="use_printf_a_for_passing_float_values">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_ksh93only; Use <literal>printf "%a"</literal> when passing floating-point values</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Use <literal>printf "%a"</literal> when passing floating-point values between scripts or
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz as output of a function to avoid rounding errors when converting between
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz bases.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Example:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfunction xxx
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz{
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz float val
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (( val=sin(5.) ))
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz printf "%a\n" val
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz}
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfloat out
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz(( out=$(xxx) ))
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzxxx
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzprint -- $out
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland MainzThis will print:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz-0.9589242747
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz-0x1.eaf81f5e09933226af13e5563bc6p-01
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="put_constants_into_readonly_variables">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly;&tag_performance;Put constant values into readonly variables</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Put constant values into readonly variables</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>For example:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfloat -r M_PI=3.14159265358979323846
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzor
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfloat M_PI=3.14159265358979323846
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzreadonly M_PI
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="avoid_unnecessary_string_number_conversions">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_kshonly;&tag_performance;Avoid string to number
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (and/or number to string) conversions in arithmetic expressions
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz expressions</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Avoid string to number and/or number to string conversions in
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz arithmetic expressions expressions to avoid performance degradation
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz and rounding errors.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <example><title>(( x=$x*2 )) vs. (( x=x*2 ))</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfloat x
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz...
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz(( x=$x*2 ))
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzwill convert the variable "x" (stored in the machine's native
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<literal>|long double|</literal> datatype) to a string value in base10 format,
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzapply pattern expansion (globbing), then insert this string into the
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzarithmetic expressions and parse the value which converts it into the internal |long double| datatype format again.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland MainzThis is both slow and generates rounding errors when converting the floating-point value between
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzthe internal base2 and the base10 representation of the string.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland MainzThe correct usage would be:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfloat x
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz...
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz(( x=x*2 ))
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainze.g. omit the '$' because it's (at least) redundant within arithmetic expressions.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </example>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <example><title>x=$(( y+5.5 )) vs. (( x=y+5.5 ))</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfloat x
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfloat y=7.1
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz...
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzx=$(( y+5.5 ))
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzwill calculate the value of <literal>y+5.5</literal>, convert it to a
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzbase-10 string value amd assign the value to the floating-point variable
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<literal>x</literal> again which will convert the string value back to the
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzinternal |long double| datatype format again.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland MainzThe correct usage would be:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfloat x
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfloat y=7.1
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz...
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz(( x=y+5.5 ))
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzi.e. this will save the string conversions and avoid any base2--&gt;base10--&gt;base2-conversions.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </example>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="set_lc_numeric_when_using_floating_point">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>&tag_ksh93only;Set <envar>LC_NUMERIC</envar> when using floating-point constants</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Set <envar>LC_NUMERIC</envar> when using floating-point constants to avoid problems with radix-point
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz representations which differ from the representation used in the script, for example the <literal>de_DE.*</literal> locale
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz use ',' instead of '.' as default radix point symbol.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>For example:
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz<programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# Make sure all math stuff runs in the "C" locale to avoid problems with alternative
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# radix point representations (e.g. ',' instead of '.' in de_DE.*-locales). This
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# needs to be set _before_ any floating-point constants are defined in this script)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzif [[ "${LC_ALL}" != "" ]] ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz export \
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz LC_MONETARY="${LC_ALL}" \
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz LC_MESSAGES="${LC_ALL}" \
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz LC_COLLATE="${LC_ALL}" \
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz LC_CTYPE="${LC_ALL}"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz unset LC_ALL
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfi
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzexport LC_NUMERIC=C
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz...
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzfloat -r M_PI=3.14159265358979323846
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</programlisting>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <note><para>The environment variable <envar>LC_ALL</envar> always overrides all other <envar>LC_*</envar> variables,
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz including <envar>LC_NUMERIC</envar>. The script should always protect itself against custom <envar>LC_NUMERIC</envar> and
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <envar>LC_ALL</envar> values as shown in the example above.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </para></note>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section><!-- end of math -->
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="misc">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Misc</title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <section xml:id="debug_use_lineno_in_ps4">
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <title>Put <literal>[${LINENO}]</literal> in your <envar>PS4</envar></title>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz <para>Put <literal>[${LINENO}]</literal> in your <envar>PS4</envar> prompt so that you will get line
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz numbers with you run with <literal>-x</literal>. If you are looking at performance
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz issues put <literal>$SECONDS</literal> in the <envar>PS4</envar> prompt as well.</para>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz </section><!-- end of misc -->
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</section><!-- end of RULES -->
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz</article>