koalaman / shellcheck

ShellCheck, a static analysis tool for shell scripts
https://www.shellcheck.net
GNU General Public License v3.0
36.22k stars 1.77k forks source link

options that change the parser's behaviour in a shell #438

Open izabera opened 9 years ago

izabera commented 9 years ago

I don't know if shellcheck understands how blocks are parsed... Can it suggest that these don't work as expected?

alias a=b; shopt -s extglob; a +(x)

{
  alias c=d
  shopt -s extglob
  c +(x)
}

func () {
  alias e=f
  shopt -s extglob
  f +(x)
}

extglob is bash specific but aliases are not.

To complicate everything, these work:

shopt -s extglob; echo "${var#+(x)}"
shopt -s extglob; echo "$( echo +(x) )"
alias a=b; c $( a )
koalaman commented 9 years ago

How do you even come across these things O___o

izabera commented 9 years ago

I use bash pretty often

izabera commented 9 years ago

On a more serious note, these things have been mentioned in #bash several times, but I only figured out recently that $( ) causes a new parsing block in bash/ksh/mksh/zsh (it doesn't in busybox/dash/yash). It's probably worth mentioning (or maybe recommend against it) because it can be tricky...

bittorf commented 8 years ago

i have a better example of a real usecase:

#!/bin/sh
alias explode='set -f --;set +f'

x()
{
  explode A * C
  echo "$3"
}

x

shellsheck must internally replace/evaluate the alias.

izabera commented 8 years ago

move -- in the other set...

bittorf commented 8 years ago

@izabera you are right, thank you. but the main problem keeps, sc is complaining:

SC2120 x references arguments, but none are ever passed. SC2119 Use x "$@" if function's $1 should mean script's $1.

mmjo commented 2 years ago

Aliases are tricky to use in scripts.

Your first line defines an alias and uses it within the same line. This may not do what you expect. Bash parses the whole line and doesn't immediately apply any aliases defined therein. Same goes for aliases within blocks and function definitions. As @temporaryrespite mentioned.

Example:

unalias lls
alias lls='ls -l'; lls   ## lls : command not found
lls ## only on the next line, the alias is recognized

unalias lls
{
  alias lls='ls -l'; lls   ## lls : command not found
  lls ## lls: command not found
}
lls ## uses the alias