ShellCheck es una herramienta GPLv3 que ofrece advertencias y sugerencias para scripts de shell bash/sh:
Las metas de ShellCheck son
- Para señalar y aclarar los típicos problemas de sintaxis de los issues hacen que un shell produzca mensajes de error crípticos.
- Para señalar y aclarar los típicos problemas semánticos de nivel intermedio que hacen que shell se comporte de forma extraña y contraintuitiva.
- Señalar las sutiles advertencias, los casos de esquina que pueden hacer que un script de un usuario avanzado que funcione de otra manera falle en circunstancias futuras.
Mira la galería de código erróneo para ver ejemplos de lo que ShellCheck puede ayudarte a identificar!
https://github.com/koalaman/shellcheck/blob/master/README.md#user-content-gallery-of-bad-code
Cómo Usar
Hay varias maneras de usar ShellCheck!
En la web
Pega un script de shell en https://www.shellcheck.net para obtener una respuesta instantánea.
ShellCheck.net siempre está sincronizado con el último git commit, y es la forma más fácil de probar ShellCheck. Cuéntale a tus amigos!
Desde tu terminal
Ejecuta shellcheck tuscript
en tu terminal para obtener una salida instantánea, como has visto arriba.
En tu editor
Puedes ver las sugerencias de ShellCheck directamente en una variedad de editores.
- Vim, a través de ALE, Neomake, o Syntastic:
https://github.com/w0rp/ale
https://github.com/neomake/neomake
https://github.com/scrooloose/syntastic
- Emacs, a través de Flycheck o Flymake:
https://github.com/flycheck/flycheck
https://github.com/federicotdn/flymake-shellcheck
- Sublime, a través de SublimeLinter (https://github.com/SublimeLinter/SublimeLinter-shellcheck).
- Atom, a través de Linter (https://github.com/AtomLinter/linter-shellcheck).
- VSCode, a través de vscode-shellcheck (https://github.com/timonwong/vscode-shellcheck).
- La mayoría de los otros editores, a través de GCC error compatibility (https://github.com/koalaman/shellcheck/blob/master/shellcheck.1.md).
En tus suites de construcción o de prueba
Aunque ShellCheck está pensado sobre todo para un uso interactivo, puede añadirse fácilmente a las construcciones o a las suites de pruebas. Hace un uso canónico de los códigos de salida, así que puedes añadir un comando shellcheck
como parte del proceso.
Por ejemplo, en un Makefile:
check-scripts:
# Fail if any of these files have warnings
shellcheck myscripts/*.sh
O en un archivo Travis CI .travis.yml
:
script:
# Fail if any of these files have warnings
- shellcheck myscripts/*.sh
Servicios y plataformas que tienen ShellCheck preinstalado y listo para usar:
- Travis CI
- Codacy
- Code Climate
- Code Factor
- CircleCI via the ShellCheck Orb
- Github (solo Linux)
https://github.com/features/actions
Servicios y plataformas con plugins de terceros:
- SonarQube a través de sonar-shellcheck-plugin:
https://github.com/emerald-squad/sonar-shellcheck-plugin
La mayoría de los demás servicios, incluido GitLab, permiten instalar ShellCheck por sí mismos, ya sea a través del administrador de paquetes del sistema (ver Installing), o descargando y desempaquetando un binary release.
https://github.com/koalaman/shellcheck#installing
https://github.com/koalaman/shellcheck#installing-a-pre-compiled-binary
Es una buena idea instalar manualmente una versión específica de ShellCheck de todas formas. Así se evitan las sorpresivas interrupciones en la construcción cuando se publica una nueva versión con nuevas advertencias.
Para filtrar o informar de forma personalizada, ShellCheck puedes producir simples JSON, XML compatible con CheckStyle, advertencias compatibles con GCC, así como texto legible para el ser humano (con o sin colores ANSI). Consulta la página wiki de Integration para obtener más documentación.
https://github.com/koalaman/shellcheck/wiki/Integration
Instalación
La forma más fácil de instalar ShellCheck localmente es a través de tu administrador de paquetes.
En los sistemas con Cabal (se instala en ~/.cabal/bin
):
stack update
stack install ShellCheck
En distros basados en Debian:
apt-get install shellcheck
En distros basados en Arch Linux:
pacman -S shellcheck
O conseguir la dependencia libre shellcheck-bin del AUR.
En distros basados en Gentoo:
emerge --ask shellcheck
En distros basados en EPEL:
yum -y install epel-release
yum install ShellCheck
En distros basados en Fedora:
dnf install ShellCheck
En FreeBSD:
pkg install hs-ShellCheck
En macOS (OS X) con Homebrew:
brew install shellcheck
En OpenBSD:
pkg_add shellcheck
En openSUSE
zypper in ShellCheck
O utiliza OneClickInstall – https://software.opensuse.org/package/ShellCheck
En Solus:
eopkg install shellcheck
En Windows (vía chocolatey):
C:\> choco install shellcheck
En Windows (vía scoop):
C:\> scoop install shellcheck
De Snap Store:
snap install --channel=edge shellcheck
De Docker Hub:
docker run --rm -v "$PWD:/mnt" koalaman/shellcheck:stable myscript
# Or :v0.4.7 for that version, or :latest for daily builds
o usa koalaman/shellcheck-alpine
si quieres que se extienda una imagen más grande basada en Alpine Linux. Funciona exactamente como una imagen Alpine normal, pero tiene Shellcheck preinstalado.
Usando el administrador de paquetes nix::
nix-env -iA nixpkgs.shellcheck
Alternativamente, puedes descargar binarios pre-compilados para la última versión aquí:
https://github.com/koalaman/shellcheck/releases
Los paquetes de los distros vienen ya con una página de manual. Si está construyendo desde la fuente, se puede instalar con:
pandoc -s -f markdown-smart -t man shellcheck.1.md -o shellcheck.1
sudo mv shellcheck.1 /usr/share/man/man1
Travis CI
Travis CI ha integrado ShellCheck por defecto, así que no es necesario instalarlo manualmente.
Si aún así quieres hacerlo para actualizar a tu gusto o asegurarte de que estás usando la última versión, sigue los pasos que se indican a continuación para instalar una versión binaria.
Instalando un binario pre-compilado
Los binarios precompilados vienen en documentos tar.xz
. Para descomprimirlos, asegúrate de que xz esté instalado. En Debian/Ubuntu/Mint, puedes instalar aptos para install xz-utils
. On Redhat/Fedora/CentOS, yum -y install xz
.
Un simple instalador puede hacer algo como:
scversion="stable" # or "v0.4.7", or "latest"
wget -qO- "https://github.com/koalaman/shellcheck/releases/download/${scversion?}/shellcheck-${scversion?}.linux.x86_64.tar.xz" | tar -xJv
cp "shellcheck-${scversion}/shellcheck" /usr/bin/
shellcheck --version
Compilación de la fuente
Esta sección describe cómo construir ShellCheck desde un directorio de origen. ShellCheck está escrito en Haskell y requiere 2GB de RAM para compilar.
Instalando Cabal
ShellCheck está construido y empaquetado usando Cabal. Instala el paquete cabal-install
del administrador de paquetes de su sistema (con e.g. apt-get,
brew
, emerge
, yum
, o zypper
).
En macOS (OS X), puedes hacer una instalación rápida de Cabal usando brew, lo cual toma un par de minutos en lugar de más de 30 minutos si tratas de compilarlo desde la fuente.
$ brew install cabal-install
En MacPorts, el paquete se llama en cambio hs-cabal-install
, mientras que los usuarios nativos de Windows deben instalar la última versión de la plataforma de Haskell desde https://www.haskell.org/platform/
Verifica que Cabal esté instalada y actualiza su lista de dependencias con
$ cabal update
Compilando ShellCheck
git clone
este repositorio, y cd
al directorio de origen de ShellCheck para construir/instalar:
$ cabal install
O si tienes la intención de hacer las pruebas:
$ cabal install --enable-tests
Esto compilará ShellCheck y lo instalará en tu directorio ~/.cabal/bin
.
Añade este directorio a tu PATH (para bash, añade esto a tu ~/.bashrc
):
export PATH="$HOME/.cabal/bin:$PATH"
Cierra la sesión y vuelve a entrar, y verifica que tu PATH esté configurado correctamente:
$ which shellcheck
~/.cabal/bin/shellcheck
En Windows nativo, el PATH
ya debería estar configurado, pero el sistema puede utilizar una página de códigos heredada. En cmd.exe
, powershell.exe
y Powershell ISE, asegúrate de usar una fuente TrueType, no una fuente Raster, y establece la página de códigos activa en UTF-8 (65001) con chcp
:
chcp 65001
En Powershell ISE, puede que tengas que actualizar adicionalmente la codificación de salida:
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
Realizando pruebas
Para ejecutar el conjunto de pruebas de la unidad:
$ cabal test
Galería de código malo
Entonces, ¿qué tipo de cosas busca ShellCheck? Aquí hay una lista incompleta de las issues detectadas.
Quoting
ShellCheck puede reconocer varios tipos de citas incorrectas:
echo $1 # Unquoted variables
find . -name *.ogg # Unquoted find/grep patterns
rm "~/my file.txt" # Quoted tilde expansion
v='--verbose="true"'; cmd $v # Literal quotes in variables
for f in "*.ogg" # Incorrectly quoted 'for' loops
touch $@ # Unquoted $@
echo 'Don't forget to restart!' # Singlequote closed by apostrophe
echo 'Don\'t try this at home' # Attempting to escape ' in ''
echo 'Path is $PATH' # Variables in single quotes
trap "echo Took ${SECONDS}s" 0 # Prematurely expanded trap
Condicionales
ShellCheck puede reconocer muchos tipos de declaraciones de pruebas incorrectas.
[[ n != 0 ]] # Constant test expressions
[[ -e *.mpg ]] # Existence checks of globs
[[ $foo==0 ]] # Always true due to missing spaces
[[ -n "$foo " ]] # Always true due to literals
[[ $foo =~ "fo+" ]] # Quoted regex in =~
[ foo =~ re ] # Unsupported [ ] operators
[ $1 -eq "shellcheck" ] # Numerical comparison of strings
[ $n && $m ] # && in [ .. ]
[ grep -q foo file ] # Command without $(..)
[[ "$$file" == *.jpg ]] # Comparisons that can't succeed
(( 1 -lt 2 )) # Using test operators in ((..))
Comandos frecuentemente mal utilizados
ShellCheck puede reconocer los casos en los que los comandos se utilizan de forma incorrecta:
grep '*foo*' file # Globs in regex contexts
find . -exec foo {} && bar {} \; # Prematurely terminated find -exec
sudo echo 'Var=42' > /etc/profile # Redirecting sudo
time --format=%s sleep 10 # Passing time(1) flags to time builtin
while read h; do ssh "$h" uptime # Commands eating while loop input
alias archive='mv $1 /backup' # Defining aliases with arguments
tr -cd '[a-zA-Z0-9]' # [] around ranges in tr
exec foo; echo "Done!" # Misused 'exec'
find -name \*.bak -o -name \*~ -delete # Implicit precedence in find
# find . -exec foo > bar \; # Redirections in find
f() { whoami; }; sudo f # External use of internal functions
Errores comunes de los principiantes
ShellCheck reconoce muchos errores de sintaxis comunes de los principiantes:
= 42 # Spaces around = in assignments
$foo=42 # $ in assignments
for $var in *; do ... # $ in for loop variables
var$n="Hello" # Wrong indirect assignment
echo ${var$n} # Wrong indirect reference
var=(1, 2, 3) # Comma separated arrays
array=( [index] = value ) # Incorrect index initialization
echo $var[14] # Missing {} in array references
echo "Argument 10 is $10" # Positional parameter misreference
if $(myfunction); then ..; fi # Wrapping commands in $()
else if othercondition; then .. # Using 'else if'
f; f() { echo "hello world; } # Using function before definition
[ false ] # 'false' being true
if ( -f file ) # Using (..) instead of test
Estilo
ShellCheck puede hacer sugerencias para mejorar el estilo:
[[ -z $(find /tmp | grep mpg) ]] # Use grep -q instead
a >> log; b >> log; c >> log # Use a redirection block instead
echo "The time is `date`" # Use $() instead
cd dir; process *; cd ..; # Use subshells instead
echo $[1+2] # Use standard $((..)) instead of old $[]
echo $(($RANDOM % 6)) # Don't use $ on variables in $((..))
echo "$(date)" # Useless use of echo
cat file | grep foo # Useless use of cat
Datos y errores de escritura
ShellCheck puede reconocer problemas relacionados con los datos y la escritura:
args="$@" # Assigning arrays to strings
files=(foo bar); echo "$files" # Referencing arrays as strings
declare -A arr=(foo bar) # Associative arrays without index
printf "%s\n" "Arguments: $@." # Concatenating strings and arrays
[[ $# > 2 ]] # Comparing numbers as strings
var=World; echo "Hello " var # Unused lowercase variables
echo "Hello $name" # Unassigned lowercase variables
cmd | read bar; echo $bar # Assignments in subshells
cat foo | cp bar # Piping to commands that don't read
printf '%s: %s\n' foo # Mismatches in printf argument count
Robustez
ShellCheck puede hacer sugerencias para mejorar la robustez de un script:
rm -rf "$STEAMROOT/"* # Catastrophic rm
touch ./-l; ls * # Globs that could become options
find . -exec sh -c 'a && b {}' \; # Find -exec shell injection
printf "Hello $name" # Variables in printf format
for f in $(ls *.txt); do # Iterating over ls output
export MYVAR=$(cmd) # Masked exit codes
case $version in 2.*) :;; 2.6.*) # Shadowed case branches
Portabilidad
ShellCheck avisará cuando se usen características no soportadas por el shebang. Por ejemplo, si configuras el shebang a #!/bin/sh
, ShellCheck advertirá sobre problemas de portabilidad similares a checkbashisms
:
echo {1..$n} # Works in ksh, but not bash/dash/sh
echo {1..10} # Works in ksh and bash, but not dash/sh
echo -n 42 # Works in ksh, bash and dash, undefined in sh
trap 'exit 42' sigint # Unportable signal spec
cmd &> file # Unportable redirection operator
read foo < /dev/tcp/host/22 # Unportable intercepted files
foo-bar() { ..; } # Undefined/unsupported function name
[ $UID = 0 ] # Variable undefined in dash/sh
local var=value # local is undefined in sh
time sleep 1 | sleep 5 # Undefined uses of 'time'
Miscelánea
ShellCheck reconoce una colección de otros issues:
PS1='\e[0;32m\$\e[0m ' # PS1 colors not in \[..\]
PATH="$PATH:~/bin" # Literal tilde in $PATH
rm “file” # Unicode quotes
echo "Hello world" # Carriage return / DOS line endings
echo hello \ # Trailing spaces after \
var=42 echo $var # Expansion of inlined environment
#!/bin/bash -x -e # Common shebang errors
echo $((n/180*100)) # Unnecessary loss of precision
ls *[:digit:].txt # Bad character class globs
sed 's/foo/bar/' file > file # Redirecting to input
while getopts "a" f; do case $f in "b") # Unhandled getopts flags
Testimonios
Al principio eres como “shellcheck es impresionante” pero luego eres como “wtf seguimos usando bash”
Alexander Tarasikov, via Twitter
Ignorando issues
Los Issues pueden ser ignorados a través de la variable ambiental, línea de comando, individualmente o globalmente dentro de un archivo:
https://github.com/koalaman/shellcheck/wiki/Ignore
Informar de los errores
Por favor, usa la sección de issue de GitHub para cualquier error o sugerencia de características.
https://github.com/koalaman/shellcheck/issues
Contribuir
Por favor, envía los patches al código o la documentación que GitHub solicite. Echa un vistazo a la DevGuide en la Wiki de ShellCheck.
https://github.com/koalaman/shellcheck/wiki/DevGuide
Las contribuciones deben estar licenciadas bajo la GPLv3 de GNU. El colaborador conserva los derechos de autor.
Copyright
ShellCheck está licenciado bajo la Licencia Pública General de GNU, v3. Una copia de esta licencia está incluida en el archivo LICENSE.
Otros recursos
- Wiki tiene largas descripciones para cada advertencia, p.e. SC2221.
- ShellCheck no intenta imponer ningún tipo de formato o estilo de sangría, así que también comprueba shfmt!
https://github.com/koalaman/shellcheck