Rev | Author | # | Line |
---|---|---|---|
2 | AristotlePagaltzis | 1 | !!! [Shell] syntax |
1 | AristotlePagaltzis | 2 | |
2 | AristotlePagaltzis | 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. |
1 | AristotlePagaltzis | 4 | |
2 | AristotlePagaltzis | 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!). |
1 | AristotlePagaltzis | 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()