shlint 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.md +6 -0
  2. data/lib/checkbashisms +111 -96
  3. metadata +2 -2
data/README.md CHANGED
@@ -22,3 +22,9 @@ shells if you're missing any.
22
22
  If you're a ruby user, can install using `gem install shlint`
23
23
 
24
24
  Any other nix platform, just drop the contents of `lib` into your `$PATH`
25
+
26
+ ## Resources
27
+
28
+ * [Portable Shell Programming](http://www.gnu.org/software/autoconf/manual/autoconf.html#Portable-Shell)
29
+ * [How to make bash scripts work in dash](http://mywiki.wooledge.org/Bashism)
30
+ * [POSIX shell specification](http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html)
@@ -1,18 +1,24 @@
1
1
  #! /usr/bin/perl -w
2
+
3
+ # This script is essentially copied from /usr/share/lintian/checks/scripts,
4
+ # which is:
5
+ # Copyright (C) 1998 Richard Braakman
6
+ # Copyright (C) 2002 Josip Rodin
7
+ # This version is
8
+ # Copyright (C) 2003 Julian Gilbey
9
+ #
10
+ # This program is free software; you can redistribute it and/or modify
11
+ # it under the terms of the GNU General Public License as published by
12
+ # the Free Software Foundation; either version 2 of the License, or
13
+ # (at your option) any later version.
2
14
  #
3
- # checkbashisms.perl
4
- #
5
- # Version: 2.0.0.2
6
- # Date: 30th January 2011
7
- #
8
- # (C) Copyright 1998-2003 Richard Braakman, Josip Rodin and Julian Gilbey
9
- # Additional programming by Mark Hobley
10
- #
11
- # This script is based on source code taken from the lintian project
12
- #
13
- # This program can be redistributed under the terms of version 2 of the
14
- # GNU General Public Licence as published by the Free Software Foundation
15
+ # This program is distributed in the hope that it will be useful,
16
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ # GNU General Public License for more details.
15
19
  #
20
+ # You should have received a copy of the GNU General Public License
21
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
22
 
17
23
  use strict;
18
24
  use Getopt::Long;
@@ -30,9 +36,13 @@ in /bin/sh scripts.
30
36
  EOF
31
37
 
32
38
  my $version = <<"EOF";
33
- This is $progname version 2.0.0.1
34
- (C) Copyright 1998-2003 Richard Braakman, Josip Rodin and Julian Gilbey
35
- Additional programming by Mark Hobley
39
+ This is $progname, from the Debian devscripts package, version ###VERSION###
40
+ This code is copyright 2003 by Julian Gilbey <jdg\@debian.org>,
41
+ based on original code which is copyright 1998 by Richard Braakman
42
+ and copyright 2002 by Josip Rodin.
43
+ This program comes with ABSOLUTELY NO WARRANTY.
44
+ You are free to redistribute this code under the terms of the
45
+ GNU General Public License, version 2, or (at your option) any later version.
36
46
  EOF
37
47
 
38
48
  my ($opt_echo, $opt_force, $opt_extra, $opt_posix);
@@ -60,8 +70,8 @@ $opt_echo = 1 if $opt_posix;
60
70
  my $status = 0;
61
71
  my $makefile = 0;
62
72
  my (%bashisms, %string_bashisms, %singlequote_bashisms);
63
- my $LEADIN = qr'(?:(?:^|[`&;(|{])\s*|(?:if|then|do|while|shell)\s+)';
64
73
 
74
+ my $LEADIN = qr'(?:(?:^|[`&;(|{])\s*|(?:if|then|do|while|shell)\s+)';
65
75
  init_hashes;
66
76
 
67
77
  foreach my $filename (@ARGV) {
@@ -81,7 +91,7 @@ foreach my $filename (@ARGV) {
81
91
  . "$check_lines_count lines\n";
82
92
  }
83
93
 
84
- unless (open C, '<', "$filename") {
94
+ unless (open C, '<', $filename) {
85
95
  warn "cannot open script $filename for reading: $!\n";
86
96
  $status |= 2;
87
97
  next;
@@ -95,6 +105,7 @@ foreach my $filename (@ARGV) {
95
105
  my $found_rules = 0;
96
106
  my $buffered_orig_line = "";
97
107
  my $buffered_line = "";
108
+
98
109
  while (<C>) {
99
110
  next unless ($check_lines_count == -1 or $. <= $check_lines_count);
100
111
 
@@ -111,11 +122,19 @@ foreach my $filename (@ARGV) {
111
122
  }
112
123
  next if $opt_force;
113
124
 
114
- if ($interpreter !~ m,/(sh|ash|hsh|posh)$,) {
115
- warn "script $filename does not appear to be a /bin/sh script\n";
125
+ if ($interpreter =~ m,/bash$,) {
126
+ warn "script $filename is already a bash script; skipping\n";
127
+ $status |= 2;
128
+ last; # end this file
129
+ }
130
+ elsif ($interpreter !~ m,/(sh|posh)$,) {
131
+ ### ksh/zsh?
132
+ warn "script $filename does not appear to be a /bin/sh script; skipping\n";
133
+ $status |= 2;
134
+ last;
116
135
  }
117
136
  } else {
118
- warn "script $filename does not appear to have a \#! interpreter line\n";
137
+ warn "script $filename does not appear to have a \#! interpreter line;\nyou may get strange results\n";
119
138
  }
120
139
  }
121
140
 
@@ -134,10 +153,10 @@ foreach my $filename (@ARGV) {
134
153
  # will be treated as part of the comment.
135
154
  # s/^(?:.*?[^\\])?$quote_string(.*)$/$1/ if $quote_string ne "";
136
155
 
137
- # skip comment lines
138
- if (m,^\s*\#, && $quote_string eq '' && $buffered_line eq '' && $cat_string eq '') {
139
- next;
140
- }
156
+ # skip comment lines
157
+ if (m,^\s*\#, && $quote_string eq '' && $buffered_line eq '' && $cat_string eq '') {
158
+ next;
159
+ }
141
160
 
142
161
  # Remove quoted strings so we can more easily ignore comments
143
162
  # inside them
@@ -156,17 +175,17 @@ foreach my $filename (@ARGV) {
156
175
 
157
176
  # Handle line continuation
158
177
  if (!$makefile && $cat_string eq '' && m/\\$/) {
159
- chop;
160
- $buffered_line .= $_;
161
- $buffered_orig_line .= $orig_line . "\n";
162
- next;
178
+ chop;
179
+ $buffered_line .= $_;
180
+ $buffered_orig_line .= $orig_line . "\n";
181
+ next;
163
182
  }
164
183
 
165
184
  if ($buffered_line ne '') {
166
- $_ = $buffered_line . $_;
167
- $orig_line = $buffered_orig_line . $orig_line;
168
- $buffered_line ='';
169
- $buffered_orig_line ='';
185
+ $_ = $buffered_line . $_;
186
+ $orig_line = $buffered_orig_line . $orig_line;
187
+ $buffered_line ='';
188
+ $buffered_orig_line ='';
170
189
  }
171
190
 
172
191
  if ($makefile) {
@@ -184,10 +203,10 @@ foreach my $filename (@ARGV) {
184
203
  $_ = $1 if $1;
185
204
  }
186
205
 
187
- # Fixes for makefiles by Raphael Geissert
188
206
  last if m%^\s*(override\s|export\s)?\s*SHELL\s*:?=\s*(/bin/)?bash\s*%;
189
- # Remove "simple" target names
190
- s/^[\w%.-]+(?:\s+[\w%.-]+)*::?//;
207
+
208
+ # Remove "simple" target names
209
+ s/^[\w%.-]+(?:\s+[\w%.-]+)*::?//;
191
210
  s/^\t//;
192
211
  s/(?<!\$)\$\((\w+)\)/\${$1}/g;
193
212
  s/(\$){2}/$1/g;
@@ -259,17 +278,17 @@ foreach my $filename (@ARGV) {
259
278
  my $otherquote = ($quote eq "\"" ? "\'" : "\"");
260
279
 
261
280
  # Remove balanced quotes and their content
262
- $templine =~ s/(^|[^\\\"](?:\\\\)*)\'[^\']*\'/$1/g;
263
- $templine =~ s/(^|[^\\\'](?:\\\\)*)\"(?:\\.|[^\\\"])+\"/$1/g;
264
-
265
- # Don't flag quotes that are themselves quoted
266
- # "a'b"
267
- $templine =~ s/$otherquote.*?$quote.*?$otherquote//g;
268
- # "\""
269
- $templine =~ s/(^|[^\\])$quote\\$quote$quote/$1/g;
270
- # \' or \"
271
- $templine =~ s/\\[\'\"]//g;
272
- my $count = () = $templine =~ /(^|(?!\\))$quote/g;
281
+ $templine =~ s/(^|[^\\\"](?:\\\\)*)\'[^\']*\'/$1/g;
282
+ $templine =~ s/(^|[^\\\'](?:\\\\)*)\"(?:\\.|[^\\\"])+\"/$1/g;
283
+
284
+ # Don't flag quotes that are themselves quoted
285
+ # "a'b"
286
+ $templine =~ s/$otherquote.*?$quote.*?$otherquote//g;
287
+ # "\""
288
+ $templine =~ s/(^|[^\\])$quote\\$quote$quote/$1/g;
289
+ # \' or \"
290
+ $templine =~ s/\\[\'\"]//g;
291
+ my $count = () = $templine =~ /(^|(?!\\))$quote/g;
273
292
 
274
293
  # If there's an odd number of non-escaped
275
294
  # quotes in the line it's almost certainly the
@@ -286,17 +305,17 @@ foreach my $filename (@ARGV) {
286
305
  # detect source (.) trying to pass args to the command it runs
287
306
  # The first expression weeds out '. "foo bar"'
288
307
  if (not $found and
289
- not m/$LEADIN\.\s+(\"[^\"]+\"|\'[^\']+\'|\$\([^)]+\)+(?:\/[^\s;]+)?)\s*(\&|\||\d?>|<|;|\Z)/
290
- and m/$LEADIN(\.\s+[^\s;\`:]+\s+([^\s;]+))/) {
291
- if ($2 =~ /^(\&|\||\d?>|<)/) {
292
- # everything is ok
293
- ;
294
- } else {
295
- $found = 1;
296
- $match = $1;
297
- $explanation = "sourced script with arguments";
298
- output_explanation($filename, $orig_line, $explanation);
299
- }
308
+ not m/$LEADIN\.\s+(\"[^\"]+\"|\'[^\']+\'|\$\([^)]+\)+(?:\/[^\s;]+)?)\s*(\&|\||\d?>|<|;|\Z)/
309
+ and m/$LEADIN(\.\s+[^\s;\`:]+\s+([^\s;]+))/) {
310
+ if ($2 =~ /^(\&|\||\d?>|<)/) {
311
+ # everything is ok
312
+ ;
313
+ } else {
314
+ $found = 1;
315
+ $match = $1;
316
+ $explanation = "sourced script with arguments";
317
+ output_explanation($filename, $orig_line, $explanation);
318
+ }
300
319
  }
301
320
 
302
321
  # Remove "quoted quotes". They're likely to be inside
@@ -362,7 +381,6 @@ foreach my $filename (@ARGV) {
362
381
  # double-quoted strings, so now remove those strings as well.
363
382
  $line =~ s/(^|[^\\\'](?:\\\\)*)\"(?:\\.|[^\\\"])+\"/$1""/g;
364
383
  $cat_line =~ s/(^|[^<\\\'-](?:\\\\)*)\"(?:\\.|[^\\\"])+\"/$1""/g;
365
-
366
384
  while (my ($re,$expl) = each %bashisms) {
367
385
  if ($line =~ m/($re)/) {
368
386
  $found = 1;
@@ -375,18 +393,19 @@ foreach my $filename (@ARGV) {
375
393
  # Only look for the beginning of a heredoc here, after we've
376
394
  # stripped out quoted material, to avoid false positives.
377
395
  if ($cat_line =~ m/(?:^|[^<])\<\<(\-?)\s*(?:[\\]?(\w+)|[\'\"](.*?)[\'\"])/) {
378
- $cat_indented = ($1 && $1 eq '-')? 1 : 0;
379
- $cat_string = $2;
380
- $cat_string = $3 if not defined $cat_string;
396
+ $cat_indented = ($1 && $1 eq '-')? 1 : 0;
397
+ $cat_string = $2;
398
+ $cat_string = $3 if not defined $cat_string;
381
399
  }
382
- }
400
+ }
383
401
  }
402
+
384
403
  warn "error: $filename: Unterminated heredoc found, EOF reached. Wanted: <$cat_string>\n"
385
- if ($cat_string ne '');
404
+ if ($cat_string ne '');
386
405
  warn "error: $filename: Unterminated quoted string found, EOF reached. Wanted: <$quote_string>\n"
387
- if ($quote_string ne '');
406
+ if ($quote_string ne '');
388
407
  warn "error: $filename: EOF reached while on line continuation.\n"
389
- if ($buffered_line ne '');
408
+ if ($buffered_line ne '');
390
409
 
391
410
  close C;
392
411
  }
@@ -463,10 +482,10 @@ sub script_is_evil_and_wrong {
463
482
 
464
483
  $ret = $. - 1;
465
484
  last;
466
- } elsif (m~\@DPATCH\@~) {
467
- $ret = $. - 1;
468
- last;
469
- }
485
+ } elsif (m~\@DPATCH\@~) {
486
+ $ret = $. - 1;
487
+ last;
488
+ }
470
489
 
471
490
  }
472
491
  close IN;
@@ -474,16 +493,15 @@ sub script_is_evil_and_wrong {
474
493
  }
475
494
 
476
495
  sub init_hashes {
477
- my $LEADIN = qr'(?:(^|[`&;(|{])\s*|(if|then|do|while|shell)\s+)';
478
496
 
479
497
  %bashisms = (
480
498
  qr'(?:^|\s+)function \w+(\s|\(|\Z)' => q<'function' is useless>,
481
- $LEADIN . qr'select\s+\w+' => q<'select' is not portable>,
499
+ $LEADIN . qr'select\s+\w+' => q<'select' is not POSIX>,
482
500
  qr'(test|-o|-a)\s*[^\s]+\s+==\s' => q<should be 'b = a'>,
483
501
  qr'\[\s+[^\]]+\s+==\s' => q<should be 'b = a'>,
484
- qr'\s\|\&' => q<pipelining is not portable>,
502
+ qr'\s\|\&' => q<pipelining is not POSIX>,
485
503
  qr'[^\\\$]\{([^\s\\\}]*?,)+[^\\\}\s]*\}' => q<brace expansion>,
486
- qr'\{\d+\.\.\d+\}' => q<brace expansion, should be $(seq a b)>,
504
+ qr'\{\d+\.\.\d+\}' => q<brace expansion, should be $(seq a b)>,
487
505
  qr'(?:^|\s+)\w+\[\d+\]=' => q<bash arrays, H[0]>,
488
506
  $LEADIN . qr'read\s+(?:-[a-qs-zA-Z\d-]+)' => q<read with option other than -r>,
489
507
  $LEADIN . qr'read\s*(?:-\w+\s*)*(?:\".*?\"|[\'].*?[\'])?\s*(?:;|$)'
@@ -494,41 +512,36 @@ sub init_hashes {
494
512
  qr'(?<![\$\(])\(\(.*\)\)' => q<'((' should be '$(('>,
495
513
  qr'(?:^|\s+)(\[|test)\s+-a' => q<test with unary -a (should be -e)>,
496
514
  qr'\&>' => q<should be \>word 2\>&1>,
497
- qr'(<\&|>\&)\s*((-|\d+)[^\s;|)}`&\\\\]|[^-\d\s]+(?<!\$)(?!\d))' =>
515
+ qr'(<\&|>\&)\s*((-|\d+)[^\s;|)}`&\\\\]|[^-\d\s]+(?<!\$)(?!\d))' =>
498
516
  q<should be \>word 2\>&1>,
499
- $LEADIN . qr'kill\s+-[^sl]\w*' => q<kill -[0-9] or -[A-Z]>,
500
- $LEADIN . qr'trap\s+["\']?.*["\']?\s+.*[1-9]' => q<trap with signal numbers>,
501
- $LEADIN . qr'trap\s+["\']?.*["\']?\s+.*ERR' => q<trap ERR>,
502
517
  qr'\[\[(?!:)' => q<alternative test command ([[ foo ]] should be [ foo ])>,
503
518
  qr'/dev/(tcp|udp)' => q</dev/(tcp|udp)>,
504
- $LEADIN . qr'alias\s' => q<alias>,
505
- $LEADIN . qr'unalias\s' => q<unalias>,
506
519
  $LEADIN . qr'builtin\s' => q<builtin>,
507
520
  $LEADIN . qr'caller\s' => q<caller>,
508
- $LEADIN . qr'complete\s' => q<complete>,
509
521
  $LEADIN . qr'compgen\s' => q<compgen>,
522
+ $LEADIN . qr'complete\s' => q<complete>,
510
523
  $LEADIN . qr'declare\s' => q<declare>,
511
524
  $LEADIN . qr'dirs(\s|\Z)' => q<dirs>,
512
525
  $LEADIN . qr'disown\s' => q<disown>,
513
526
  $LEADIN . qr'enable\s' => q<enable>,
514
- $LEADIN . qr'export\s+-[^p]' => q<export only takes -p as an option>,
515
- $LEADIN . qr'export\s+.+=' => q<export foo=bar should be foo=bar; export foo>,
516
527
  $LEADIN . qr'mapfile\s' => q<mapfile>,
517
528
  $LEADIN . qr'readarray\s' => q<readarray>,
518
- $LEADIN . qr'readonly\s+-[af]' => q<readonly -[af]>,
519
- $LEADIN . qr'(push|pop)d(\s|\Z)' => q<(push|pop)d>,
520
- $LEADIN . qr'set\s+-[BHT]+' => q<set -[BHT]>,
521
529
  $LEADIN . qr'shopt(\s|\Z)' => q<shopt>,
522
530
  $LEADIN . qr'suspend\s' => q<suspend>,
523
531
  $LEADIN . qr'time\s' => q<time>,
524
532
  $LEADIN . qr'type\s' => q<type>,
525
- $LEADIN . qr'typeset\s' => q<typeset>,
533
+ $LEADIN . qr'typeset\s' => q<typeset>,
526
534
  $LEADIN . qr'ulimit(\s|\Z)' => q<ulimit>,
535
+ $LEADIN . qr'set\s+-[BHT]+' => q<set -[BHT]>,
536
+ $LEADIN . qr'alias\s+-p' => q<alias -p>,
537
+ $LEADIN . qr'unalias\s+-a' => q<unalias -a>,
527
538
  $LEADIN . qr'local\s+-[a-zA-Z]+' => q<local -opt>,
528
539
  qr'(?:^|\s+)\s*\(?\w*[^\(\w\s]+\S*?\s*\(\)\s*([\{|\(]|\Z)'
529
540
  => q<function names should only contain [a-z0-9_]>,
541
+ $LEADIN . qr'(push|pop)d(\s|\Z)' => q<(push|pop)d>,
542
+ $LEADIN . qr'export\s+-[^p]' => q<export only takes -p as an option>,
530
543
  qr'(?:^|\s+)[<>]\(.*?\)' => q<\<() process substituion>,
531
- qr'(?:^|\s+)readonly\s+-[af]' => q<readonly -[af]>,
544
+ $LEADIN . qr'readonly\s+-[af]' => q<readonly -[af]>,
532
545
  $LEADIN . qr'(sh|\$\{?SHELL\}?) -[rD]' => q<sh -[rD]>,
533
546
  $LEADIN . qr'(sh|\$\{?SHELL\}?) --\w+' => q<sh --long-option>,
534
547
  $LEADIN . qr'(sh|\$\{?SHELL\}?) [-+]O' => q<sh [-+]O>,
@@ -536,11 +549,13 @@ sub init_hashes {
536
549
  $LEADIN . qr'printf\s+-v' => q<'printf -v var ...' should be var='$(printf ...)'>,
537
550
  $LEADIN . qr'coproc\s' => q<coproc>,
538
551
  qr';;?&' => q<;;& and ;& special case operators>,
552
+ $LEADIN . qr'jobs\s' => q<jobs>,
553
+ # $LEADIN . qr'jobs\s+-[^lp]\s' => q<'jobs' with option other than -l or -p>,
554
+ $LEADIN . qr'command\s+-[^p]\s' => q<'command' with option other than -p>,
539
555
  );
540
556
 
541
557
  %string_bashisms = (
542
- qr'\$\[[^][]+\]' => q<'$[' should be '$(('>,
543
- qr'\$\[\w+\]' => q<arithmetic not allowed>,
558
+ qr'\$\[[^][]+\]' => q<'$[' should be '$(('>,
544
559
  qr'\$\{\w+\:\d+(?::\d+)?\}' => q<${foo:3[:1]}>,
545
560
  qr'\$\{!\w+[\@*]\}' => q<${!prefix[*|@]>,
546
561
  qr'\$\{!\w+\}' => q<${!name}>,
@@ -552,27 +567,25 @@ sub init_hashes {
552
567
  qr'\$\{?DIRSTACK\}?\b' => q<$DIRSTACK>,
553
568
  qr'\$\{?EUID\}?\b' => q<$EUID should be "$(id -u)">,
554
569
  qr'\$\{?UID\}?\b' => q<$UID should be "$(id -ru)">,
555
- qr'\$\{?LINENO\}?\b' => q<$LINENO>,
556
570
  qr'\$\{?SECONDS\}?\b' => q<$SECONDS>,
557
571
  qr'\$\{?BASH_[A-Z]+\}?\b' => q<$BASH_SOMETHING>,
558
- qr'\$\{?KSH_[A-Z]+\}?\b' => q<$KSH_SOMETHING>,
559
572
  qr'\$\{?SHELLOPTS\}?\b' => q<$SHELLOPTS>,
560
573
  qr'\$\{?PIPESTATUS\}?\b' => q<$PIPESTATUS>,
561
574
  qr'\$\{?SHLVL\}?\b' => q<$SHLVL>,
562
575
  qr'<<<' => q<\<\<\< here string>,
576
+ $LEADIN . qr'echo\s+(?:-[^e\s]+\s+)?\"[^\"]*(\\[abcEfnrtv0])+.*?[\"]' => q<unsafe echo with backslash>,
563
577
  qr'\$\(\([\s\w$*/+-]*\w\+\+.*?\)\)' => q<'$((n++))' should be '$n; $((n=n+1))'>,
564
578
  qr'\$\(\([\s\w$*/+-]*\+\+\w.*?\)\)' => q<'$((++n))' should be '$((n=n+1))'>,
565
579
  qr'\$\(\([\s\w$*/+-]*\w\-\-.*?\)\)' => q<'$((n--))' should be '$n; $((n=n-1))'>,
566
580
  qr'\$\(\([\s\w$*/+-]*\-\-\w.*?\)\)' => q<'$((--n))' should be '$((n=n-1))'>,
567
- qr'\$\(\([\s\w$*/+-]*\*\*.*?\)\)' => q<exponentiation is not POSIX>,
568
- $LEADIN . qr'echo\s+(?:-[^e\s]+\s+)?\"[^\"]*(\\[abcEfnrtv0])+.*?[\"]' => q<unsafe echo with backslash>,
581
+ qr'\$\(\([\s\w$*/+-]*\*\*.*?\)\)' => q<exponentiation is not POSIX>,
569
582
  $LEADIN . qr'printf\s["\'][^"\']+?%[qb].+?["\']' => q<printf %q|%b>,
570
583
  );
571
584
 
572
585
  %singlequote_bashisms = (
573
586
  $LEADIN . qr'echo\s+(?:-[^e\s]+\s+)?\'[^\']*(\\[abcEfnrtv0])+.*?[\']' => q<unsafe echo with backslash>,
574
- $LEADIN . qr'source\s+[\"\']?(?:\.\/|\/|\$|[\w~.-])\S*' =>
575
- q<should be '.', not 'source'>,
587
+ $LEADIN . qr'source\s+[\"\']?(?:\.\/|\/|\$|[\w~.-])\S*' =>
588
+ q<should be '.', not 'source'>,
576
589
  );
577
590
 
578
591
  if ($opt_echo) {
@@ -583,6 +596,8 @@ sub init_hashes {
583
596
  $bashisms{$LEADIN . qr'local\s+\w+='} = q<local foo=bar>;
584
597
  $bashisms{$LEADIN . qr'local\s+\w+\s+\w+'} = q<local x y>;
585
598
  $bashisms{$LEADIN . qr'((?:test|\[)\s+.+\s-[ao])\s'} = q<test -a/-o>;
599
+ $bashisms{$LEADIN . qr'kill\s+-[^sl]\w*'} = q<kill -[0-9] or -[A-Z]>;
600
+ $bashisms{$LEADIN . qr'trap\s+["\']?.*["\']?\s+.*[1-9]'} = q<trap with signal numbers>;
586
601
  }
587
602
 
588
603
  if ($makefile) {
@@ -592,7 +607,7 @@ sub init_hashes {
592
607
  $bashisms{$LEADIN . qr'\w+\+='} = q<should be VAR="${VAR}foo">;
593
608
  $string_bashisms{qr'(\$\(|\`)\s*\<\s*\S+\s*(\)|\`)'} = q<'$(\< foo)' should be '$(cat foo)'>;
594
609
  }
595
-
610
+
596
611
  if ($opt_extra) {
597
612
  $string_bashisms{qr'\$\{?BASH\}?\b'} = q<$BASH>;
598
613
  $string_bashisms{qr'(?:^|\s+)RANDOM='} = q<RANDOM=>;
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shlint
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-24 00:00:00.000000000 Z
12
+ date: 2012-10-25 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Checks the syntax of your shellscript against known and available shells.
15
15
  email: