| || |
The utility programs commonly executed by shell scripts can have a huge impact on the portability of shell scripts, and it is important to know which utilities are universally available, and any differences certain implementations of these utilities may exhibit. According to the GNU standards document, you can rely on having access to these utilities from your scripts:
| || |
cat cmp cp diff echo egrep expr false grep install-info ln ls mkdir mv pwd rm rmdir sed sleep sort tar test touch true
Here are some things that you must be aware of when using some of the tools listed above:
- Host architectures supply
cat implementations with conflicting interpretations of, or entirely missing, the various command line options. You should avoid using any ocommand line options to this command.
- Unconditionally duplicated or otherwise open file descriptors can not be deleted on many operating systems, and worse on Windows the destination files cannot even be moved. Constructs like this must be avoided, for example.
echo command has at least two flavors: the one takes a `-n' option to suppress the automatic newline at the end of the echoed string; the other uses an embedded `\c' notation as the last character in the echoed string for the same purpose.
If you need to emit a string without a trailing newline character, you can use the following script fragment to discover which flavor of
echo you are using:
| || |
case echo "testing\c"`,`echo -n testing` in *c*,-n*) echo_n= echo_c='(53) ' ;; *c*,*) echo_n=-n echo_c= ;; *) echo_n= echo_c='\c ;; esac
echo command after the shell fragment above, which shouldn't move the cursor to a new line, can now be written like so:
| || |
echo $echo_n "prompt:$echo_c"
In addition, you should try to avoid backslashes in
echo arguments unless they are expanded by the shell. Some implementations interpret them and effectively perform another backslash expansion pass, where equally many implementations do not. This can become a really hairy problem if you need to have an
echo command which doesn't perform backslash expansion, and in fact the first 150 lines of the
ltconfig script distributed with Libtool are devoted to finding such a command.
- Not all systems support soft links. You should use the Autoconf macro `AC_PROG_LN_S' to discover what the target architecture supports, and assign the result of that test to a variable. Whenever you subsequently need to create a link you can use the command stored in the variable to do so.
| || |
LN_S=@LN_S@ ... $LN_S $top_srcdir/foo $dist_dir/foo
Also, you cannot rely on support for the `-f' option from all implementations of
ln . Use
rm before calling
- Unfortunately, `mkdir -p' is not as portable as we might like. You must either create each directory in the path in turn , or use the
mkinstalldirs script supplied by Automake.
- When you resort to using
sed (rather, use
expr if you can), there is no need to introduce command line scripts using the `-e' option. Even when you want to supply more than one script, you can use `;' as a command separator. The following two lines are equivalent, though the latter is cleaner:
| || |
$ sed -e 's/foo/bar/g -e '12q' < infile > outfile $ sed 's/foo/bar/g;12q' < infile > outfile
Some portability zealots still go to great lengths to avoid here documents of more than twelve lines. The twelve line limit is actually a limitation in some implementations of
sed , which has gradually seeped into the portable shell folklore as a general limit in all here documents. Autoconf, however, includes many here documents with far more than twelve lines, and has not generated any complaints from users. This is testament to the fact that at worst the limit is only encountered in very obscure cases -- and most likely that it is not a real limit after all.
Also, be aware that branch labels of more than eight characters are not portable to some imlementations of
Here documents are a way of redirecting literal strings into the standard input of a command. You have certainly seen them before if you have looked at other peoples shell scripts, though you may not have realised what they were called:
| || |
cat >> /tmp/file$$ << _EOF_ This is the text of a "here document" _EOF_
Something else to be aware of is that the temporary files created by your scripts can become a security problem if they are left in `/tmp' or if the names are predictable. A simple way around this is to create a directory in `/tmp' that is unique to the process and owned by the process user . Some machines have a utility program for just this purpose --
mktemp -d -- or else you can always fall back to
umask 077 && mkdir /tmp/$$ . Having created this directory, all of the temporary files for this process should be written to that directory, and its contents removed as soon as possible.
Armed with the knowledge of how to write shell code in a portable fashion as discussed in this chapter, in combination with the M4 details from the last chapter, the specifics of combining the two to write your own Autoconf macros are covered in the next chapter.