| Rev | Author | # | Line |
|---|---|---|---|
| 2 | AristotlePagaltzis | 1 | !!! [Shell] syntax |
| 1 | AristotlePagaltzis | 2 | |
| 3 | Since the default [Shell] on almost all LinuxDistribution~s is bash(1), this page lists some common bash-isms that might fail on other sh-type shells on other [Unix](-like) OperatingSystem~s. If there is even the remote possibility that your script might be used by someone other than you, it's worth putting in a small bit of effort to use more portable constructs. | ||
| 4 | |||
| 5 | This little section is quoted from the documentation for autoconf(1) (do <tt>info autoconf</tt>, although personally I hate info pages). This demonstrates how stable the [Unix] programming environment is (don't use "new" features added since 1977!). | ||
| 6 | |||
| 2 | AristotlePagaltzis | 7 | > ! Portable Shell Programming |
| 8 | > | ||
| 9 | > When writing your own checks, there are some shell-script programming | ||
| 10 | > techniques you should avoid in order to make your code portable. The Bourne | ||
| 11 | > shell and upward-compatible shells like the Korn shell and Bash have evolved | ||
| 12 | > over the years, but to prevent trouble, do not take advantage of features | ||
| 13 | > that were added after UNIX version 7, circa 1977 . | ||
| 14 | > | ||
| 15 | > You should not use shell functions, aliases, negated character classes, or | ||
| 16 | > other features that are not found in all Bourne-compatible shells; restrict | ||
| 17 | > yourself to the lowest common denominator. Even <tt>unset</tt> is not supported | ||
| 18 | > by all shells! Also, include a space after the exclamation point in interpreter | ||
| 19 | > specifications, like this: | ||
| 20 | > | ||
| 21 | > <verbatim> | ||
| 22 | > #! /usr/bin/perl | ||
| 23 | > </verbatim> | ||
| 24 | > | ||
| 25 | > If you omit the space before the path, then 4.2BSD based systems (such as | ||
| 26 | > DYNIX) will ignore the line, because they interpret "<tt>#! /</tt>" as a | ||
| 27 | > 4-byte magic number. Some old systems have quite small limits on the length | ||
| 28 | > of the <tt>#!</tt> line too, for instance 32 bytes (not including the | ||
| 29 | > newline) on SunOS 4. | ||
| 30 | |||
| 31 | !! The test(1) command | ||
| 32 | |||
| 33 | Note that test(1) is a built-in function in many shells. | ||
| 34 | |||
| 35 | ! <i><tt>-z</tt>: tests if the length of STRING is zero</i> | ||
| 36 | |||
| 37 | In bash, a non-existent variable is treated like "", but on some other shells it is treated like nothing. | ||
| 38 | |||
| 39 | Bash, non-portable:: | ||
| 40 | |||
| 41 | <verbatim> | ||
| 42 | $ test -z $NON_EXISTENT_VARIABLE | ||
| 43 | $ echo $? | ||
| 44 | 0 | ||
| 45 | </verbatim> | ||
| 46 | |||
| 47 | Bash, more portable:: | ||
| 48 | |||
| 49 | <verbatim> | ||
| 50 | $ test -z "$NON_EXISTENT_VARIABLE" | ||
| 51 | $ echo $? | ||
| 52 | 0 | ||
| 53 | </verbatim> | ||
| 54 | |||
| 55 | Solaris sh:: | ||
| 56 | |||
| 57 | <verbatim> | ||
| 58 | $ test -z $NON_EXISTENT_VARIABLE | ||
| 59 | test: argument expected | ||
| 60 | $ echo $? | ||
| 61 | 1 | ||
| 62 | $ test -z "$NON_EXISTENT_VARIABLE" | ||
| 63 | $ echo $? | ||
| 64 | 0 | ||
| 65 | </verbatim> | ||
| 66 | |||
| 67 | ! <i><tt>-e</tt>: FILE exists</i> | ||
| 68 | |||
| 69 | This seems to be a [GNU] extension – some shells don't allow <tt>-e</tt> as an option to test. | ||
| 70 | |||
| 71 | Solaris sh:: | ||
| 72 | |||
| 73 | <verbatim> | ||
| 74 | $ test -e filename | ||
| 75 | test: argument expected | ||
| 76 | </verbatim> | ||
| 77 | |||
| 78 | In most cases, you can use <tt>-r</tt> (for file is readable) instead. | ||
| 79 | |||
| 80 | !! Variables | ||
| 81 | |||
| 82 | Bash, non-portable: | ||
| 83 | |||
| 84 | <verbatim> | ||
| 85 | $ export VAR1=foo | ||
| 86 | $ echo $VAR1 | ||
| 87 | foo | ||
| 88 | </verbatim> | ||
| 89 | |||
| 90 | Bash, more portable: | ||
| 91 | |||
| 92 | <verbatim> | ||
| 93 | $ VAR2=bar; export VAR2 | ||
| 94 | $ echo $VAR2 | ||
| 95 | bar | ||
| 96 | </verbatim> | ||
| 97 | |||
| 98 | Solaris sh: | ||
| 99 | |||
| 100 | <verbatim> | ||
| 101 | $ export VAR1=foo | ||
| 102 | VAR1=foo is not an indentifier | ||
| 103 | $ echo $VAR1 | ||
| 104 | $ VAR2=bar; export VAR2 | ||
| 105 | $ echo $VAR2 | ||
| 106 | bar | ||
| 107 | </verbatim> | ||
| 4 | AristotlePagaltzis | 108 | |
| 109 | !! See also | ||
| 110 | |||
| 111 | * [What to watch out for when writing portable shell scripts | http://programming.newsforge.com/article.pl?sid=04/03/01/1554205], a useful article on NewsForge | ||
| 2 | AristotlePagaltzis | 112 | |
| 113 | ---- | ||
| 114 | |||
| 115 | !!! [Shell] tools | ||
| 116 | |||
| 117 | !! tar(1) | ||
| 118 | |||
| 119 | tar(1) on [BSD] systems (including [MacOSX]) need an explicit dash (-) before the options, whereas [GNU] tar doesn't. Eg.: | ||
| 120 | |||
| 121 | <verbatim> | ||
| 1 | AristotlePagaltzis | 122 | $ tar xf file.tar (gnu) |
| 123 | $ tar -xf file.tar (bsd) | ||
| 2 | AristotlePagaltzis | 124 | </verbatim> |
| 1 | AristotlePagaltzis | 125 | |
| 2 | AristotlePagaltzis | 126 | Not all tars support the <tt>-z</tt> option for [gzip(1)]ped TarBall~s. Pipe it instead. (Not all environments have the zcat(1) alias either.) |
| 127 | |||
| 128 | <verbatim> | ||
| 1 | AristotlePagaltzis | 129 | $ tar -zxf file.tar.gz # not portable |
| 130 | $ gzip -d -c file.tar.gz | tar -xf - | ||
| 2 | AristotlePagaltzis | 131 | </verbatim> |
| 132 | |||
| 133 | ---- | ||
| 134 | |||
| 135 | !!! [C] | ||
| 136 | |||
| 137 | !! File locking | ||
| 138 | |||
| 139 | [BSD]-style unixes uses flock(2), which uses "advisory" locks. Ie, a process with sufficient read or write permission can ignore the lock and read/write a file. [SysV]-style unixes use either advisory locks or "mandatory" locks (if enabled in the FileSystem), and access them by the fcntl(2) command and a <tt>struct flock</tt> object. | ||
| 140 | |||
| 141 | A more portable way ([POSIX] 1003.1-2001) is to use the lockf(3) function from unistd.h, which will do the correct type of locking for the unix it is compiled on. (In [Linux]/[GNU] libc, this function is a wrapper around fcntl(2)). | ||
| 142 | |||
| 143 | !! printf(3) types | ||
| 144 | |||
| 145 | ! 64-bit-isms and fixed sized types | ||
| 146 | |||
| 147 | If you have a fixed sized type (eg, uint64_t) and you want to use printf(3) to display it, you need to know the real type of the integer. Eg.: | ||
| 148 | |||
| 149 | <verbatim> | ||
| 150 | uint64_t x; | ||
| 151 | printf("%llu",x); | ||
| 152 | </verbatim> | ||
| 153 | |||
| 154 | This however will fail on 64bit machines as <tt>uint64_t</tt> is <tt>long</tt> not <tt>long long</tt>. | ||
| 155 | |||
| 156 | [POSIX] defines some macros to use in this case, normally found in <tt>inttypes.h</tt>. Eg., for an unsigned 64 bit value, use the macro <tt>PRIu64</tt>. This will be substituted for whatever is appropriate on your host – either <tt>lu</tt> or <tt>llu</tt>, depending on if you are on a 32bit or 64bit host. Eg.: | ||
| 157 | |||
| 158 | <verbatim> | ||
| 159 | uint64_t x; | ||
| 160 | printf("%"PRIu64,x); | ||
| 161 | </verbatim> | ||
| 3 | PerryLorier | 162 | |
| 163 | ! Avoid using other peoples types in your headers | ||
| 164 | Other peoples types change in size, sometimes at the flick of a #define. One example is off_t changes if LARGEFILE64 is defined under Linux. Use the c99 <tt><stdint.h></tt> types (uint64_t) so that they don't vary. If you absolutely must reference someone elses type, do so via a pointer (eg FILE*) and treat it as opaque. | ||
| 2 | AristotlePagaltzis | 165 | |
| 166 | !! See also | ||
| 167 | |||
| 168 | * [HP] has [a set of C portability notes | http://docs.hp.com/en/5074/portability.html], although it targets HP-UX. | ||
| 169 | * [Intel] has [a similar set of notes | http://www.intel.com/cd/ids/developer/asmo-na/eng/technologies/64bit/200519.htm?page=1] (for porting to [ia64] and [amd64]) | ||
| 1 | AristotlePagaltzis | 170 | |
| 171 | ---- | ||
| 172 | Part of CategoryProgramming |
lib/blame.php:177: Warning: Invalid argument supplied for foreach()