shlint 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: