[Перевод] Статический анализатор ShellCheck и улучшение качества скриптов в Linux и Unix

0cxz0ifjvhrbzqopo5phtxrdsw8.png

Написание shell-скриптов — занятие увлекательное. Скрипты командной строки помогают автоматизировать повседневные дела. Можно создать нечто прекрасное (или какую-нибудь гадость), однако, если уж что-то писать, хорошо бы точно знать, что код получается именно таким, каким он нужен программисту. Скрипт, написанный некачественно, может представлять опасность. Большинство новичков пишут скрипты, копируя фрагменты кода со StackOverflow, находя то, что им нужно, в Google, или пользуясь сайтами с вопросами и ответами по Linux. Такой подход к программированию выливается в некачественный код и в появление ошибок. Вот, например, команда rm, выполнение которой приведёт к катастрофе, так как переменная VAR не определена:

rm -rf "/$VAR/*"


Многие из проблем скриптов можно решить с помощью линтера, такого, как статический анализатор кода ShellCheck, который написан на Haskell. Он помогает искать ошибки в текстах скриптов и выводить отчёты о проведённых проверках. Это позволяет повысить производительность работы и качество кода. Сегодня мы расскажем о том, как установить и использовать ShellCheck в Linux и Unix-подобных операционных системах.

Установка


Самый простой способ локальной установки ShellCheck заключается в использовании применяемого в вашем дистрибутиве менеджера пакетов вроде apt/apt-get/yum и других.

▍Установка ShellCheck в Debian/Ubuntu Linux


Тут понадобится следующая команда apt / apt-get:

$ sudo apt install shellcheck


Вот пример реакции системы на эту команду:

[sudo] password for vivek: 
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  shellcheck
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 1,841 kB of archives.
After this operation, 15.5 MB of additional disk space will be used.
Get:1 http://in.archive.ubuntu.com/ubuntu artful/universe amd64 shellcheck amd64 0.4.6-1 [1,841 kB]
Fetched 1,841 kB in 42s (43.4 kB/s)
Selecting previously unselected package shellcheck.
(Reading database ... 196100 files and directories currently installed.)
Preparing to unpack .../shellcheck_0.4.6-1_amd64.deb ...
Unpacking shellcheck (0.4.6-1) ...
Setting up shellcheck (0.4.6-1) ...
Processing triggers for man-db (2.7.6.1-2) ...


▍Установка ShellCheck в CentOS/RHEL/Fedora/Oracle Linux


Сначала нужно включить репозиторий EPEL в CentOS/RHEL:

$ sudo yum -y install epel-release


Дальше надо ввести следующую команду yum:

$ sudo yum install ShellCheck


Вот что будет выведено в ответ на эту команду:

Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: centos.excellmedia.net
 * epel: mirror.nes.co.id
 * extras: mirrors.vonline.vn
 * updates: centos-hcm.viettelidc.com.vn
Resolving Dependencies
--> Running transaction check
---> Package ShellCheck.x86_64 0:0.3.5-1.el7 will be installed
--> Processing Dependency: ghc(ShellCheck-0.3.5-297097a7f5fa37100847be7f096be51e) for package: ShellCheck-0.3.5-1.el7.x86_64
.....
..
...
Dependencies Resolved
 
===============================================================================
 Package                Arch         Version                  Repository  Size
===============================================================================
Installing:
 ShellCheck             x86_64       0.3.5-1.el7              epel       495 k
Installing for dependencies:
 ghc-ShellCheck         x86_64       0.3.5-1.el7              epel       540 k
 ghc-array              x86_64       0.4.0.1-26.4.el7         epel       113 k
 ghc-base               x86_64       4.6.0.1-26.4.el7         epel       1.6 M
 ghc-bytestring         x86_64       0.10.0.2-26.4.el7        epel       182 k
 ghc-containers         x86_64       0.5.0.0-26.4.el7         epel       287 k
 ghc-deepseq            x86_64       1.3.0.1-26.4.el7         epel        45 k
 ghc-directory          x86_64       1.2.0.1-26.4.el7         epel        59 k
 ghc-filepath           x86_64       1.3.0.1-26.4.el7         epel        60 k
 ghc-json               x86_64       0.7-4.el7                epel        96 k
 ghc-mtl                x86_64       2.1.2-27.el7             epel        33 k
 ghc-old-locale         x86_64       1.0.0.5-26.4.el7         epel        50 k
 ghc-parsec             x86_64       3.1.3-31.el7             epel       105 k
 ghc-pretty             x86_64       1.1.1.0-26.4.el7         epel        57 k
 ghc-regex-base         x86_64       0.93.2-29.el7            epel        28 k
 ghc-regex-compat       x86_64       0.95.1-35.el7            epel        15 k
 ghc-regex-posix        x86_64       0.95.2-30.el7            epel        47 k
 ghc-syb                x86_64       0.4.0-35.el7             epel        39 k
 ghc-text               x86_64       0.11.3.1-2.el7           epel       379 k
 ghc-time               x86_64       1.4.0.1-26.4.el7         epel       187 k
 ghc-transformers       x86_64       0.3.0.0-34.el7           epel       100 k
 ghc-unix               x86_64       2.6.0.1-26.4.el7         epel       160 k
 
Transaction Summary
===============================================================================
Install  1 Package (+21 Dependent packages)
 
Total download size: 4.6 M
Installed size: 28 M
Is this ok [y/d/N]: y
Downloading packages:
(1/22): ghc-bytestring-0.10.0.2-26.4.el7.x86_64.rpm       | 182 kB   00:09     
(2/22): ghc-array-0.4.0.1-26.4.el7.x86_64.rpm             | 113 kB   00:09     
....
..
...
  ghc-parsec.x86_64 0:3.1.3-31.el7                                             
  ghc-pretty.x86_64 0:1.1.1.0-26.4.el7                                         
  ghc-regex-base.x86_64 0:0.93.2-29.el7                                        
  ghc-regex-compat.x86_64 0:0.95.1-35.el7                                      
  ghc-regex-posix.x86_64 0:0.95.2-30.el7                                       
  ghc-syb.x86_64 0:0.4.0-35.el7                                                
  ghc-text.x86_64 0:0.11.3.1-2.el7                                             
  ghc-time.x86_64 0:1.4.0.1-26.4.el7                                           
  ghc-transformers.x86_64 0:0.3.0.0-34.el7                                     
  ghc-unix.x86_64 0:2.6.0.1-26.4.el7                                           
 
Complete!


Если вы пользуетесь Fedora, выполните следующую команду dnf:

$ sudo dnf install ShellCheck


▍Установка ShellCheck в Arch Linux


Введите следующую команду pacman:

$ sudo pacman -S shellcheck


▍Установка ShellCheck в Gentoo Linux


Введите такую команду emerge:

$ sudo emerge --ask shellcheck


▍Установка ShellCheck в OpenSUSE Linux


Введите следующую команду zypper:

$ sudo zypper in ShellCheck


▍Установка ShellCheck в macOS Unix


Воспользуйтесь следующей командой port если вы работаете с MacPorts:

$ port install shellcheck


Если вы пользуетесь Homebrew в macOS/OS X, введите такую команду brew:

$ brew install shellcheck


Как пользоваться ShellCheck


Испытаем ShellCheck на скрипте, содержимое которого просмотрим с помощью команды cat:

$ cat -n backupme


Вот его код:

#!/bin/bash
t="/tmp/exclude.$$"
source ~/.backup.conf
>$t
for w in $WHATNOT
do
    echo $w >> $t
done
rsync $OPT -avr --exclude-from=$t  $WHAT $SERVER:$WHERE
rm -rf $t


Теперь проверим скрипт с помощью ShellCheck:

$ shellcheck backupme


В ответ программа выдаст следующее:

f36394d80daad6bb8a7fa9f03c258279.png
ShellCheck в действии

Утилита ShellCheck предложила внести исправления, касающиеся использования переменных, не заключённых в кавычки, а также сообщила о других проблемах. Исправим ошибки и снова просмотрим текст скрипта следующей командой:

$ cat -n backupme


Вот что, в итоге, получилось:

#!/bin/bash
t="/tmp/exclude.$$"
source ~/.backup.conf
touch $t
for w in $WHATNOT
do
    echo "$w" >> $t
done
rsync "$OPT" -avr --exclude-from=$t  "$WHAT" "$SERVER:$WHERE"
rm -rf "$t"


Интеграция ShellCheck в текстовый редактор


ShellCheck можно интегрировать в vim или emacs, в результате, он будет проверять тексты скриптов прямо в редакторе. Тут показано применение плагина для vim neomake, асинхронного средства для линтинга и сборки программ. Он был установлен с использованием менеджера плагинов vim-plug в ~/.vimrc:

call plug#begin('~/.vim/plugged')
Plug 'pearofducks/ansible-vim'
" install and use neomake linting
Plug 'neomake/neomake'
call plug#end()


Для установки ansible-vim и neomake/neomake, введите в vim следующую команду:

:PlugInstall


Для использования плагина введите следующую команду, редактируя bash/sh-скрипт:

:Neomake


Вот как выглядят результаты работы плагина в редакторе:

fe752cca007c9176e19e93a85c13fe93.png


Neomake выводит предупреждения и сообщения об ошибках с помощью ShellCheck

Итоги


Полагаем, ShellCheck — это замечательный инструмент, который позволяет улучшать и исправлять скрипты командной строки Linux. Он способен обнаруживать множество распространённых недоработок и ошибок в их коде. Если вы хотите узнать о SpellCheck больше — вот сайт проекта, а вот — его репозиторий на GitHub.

Уважаемые читатели! Проверяете ли вы свои скрипты чем-то вроде ShellCheck?

© Habrahabr.ru