ShellCheck


finds bugs in your shell scripts.
You can cabal, apt, dnf, pkg or brew install it locally right now.
Paste a script to try it out:
📄
Your Editor (Ace – loading 800kb of JS)
 
#!/usr/bin/dash

#    #  ####  #
#    # #    # #     
#    # #    # #
#    # #    # #
 #  #  #    # #
  ##    ####  ######

# simple way to control volume from shell or key binding


# Author: Violet
# Last Change: 08 April 2023

# Notes:
# [1] if this script is called from a noninteractive context (ie, from a
#     keybinding in your window manager), it will use notify-send if an X
#     session is detected). Please run dunst or some other notification manager.
#     Otherwise, this script will hang on notify-send. This script will always
#     use notify-send from a noninteractive session if -n is passed but not if
#     an X session isn't detected. However, it will call notify-send if -nn is
#     passed.
#
# [2] -q simply sets verbosity to 0; a following -v will reset it to the default
#     of 1, and further -v flags will increase the verbosity again. The initial
#     verbosity is also initially based on whether the script is called
#     interactively or not. If the script is called from an interactive
#     environment, then the verbosity is 1 initially; otherwise, it's initially
#     0. Similarly, notify is set to 1 if called noninteractively or 0
#     otherwise. To force verbosity to be exactly one in both contexts, use -qv
#     since -q sets verbosity=0 and -v increments verbosity by one. Similarly,
#     you can do -Nn to reset notify=0 with -N and increse notify by one with
#     -n.


version=1.4;
script="$(basename "$0")";

debug(){
  if [ $verb -gt "$1" ];
  then
    >&2 printf "[debug%d] %s\n" "$1" "$2";
  fi;
};

getVol(){
  read vol on_off <<EOF
  $(amixer get $_card "$mixer" 2>/tmp/vol.error \
    | perl -n -e '/\[(\d+)%\].*\[(on|off)\]$/ && print("$1 $2\n") && exit')
EOF
  if [ "$on_off" = 'off' ]
  then
    mutestr='(muted)';
  else
    mutestr='';
  fi;
};

usage(){
  if [ "${1:-1}" -eq 0 ];
  then
    figlet -k -f banner vol 2>/dev/null;
    printf "Easily see and change the volume with amixer\n\n";
  fi;
cat <<__EOF
Usage: $script;  $script -h;  $script -V;
       $script [-rmutqvnN] [-x mixer] [-c card] [vol[+-]];
       $script -d [-rmutqvnN] [-x mixer] [-c card] [+-];

Options:
  -r  =>  round volume to nearest multiple of 5
  -d  =>  dynamically increase/decrease volume (coming soon)
  
  -m, -u, -t  =>  mute, unmute, toggle mute (resp) in order of precedence
  
  -q    =>  quiet
  -v    =>  increase verbosity (max: -vvv)
  -n    =>  increase notifiability for notify-send (max: -nn)
            note: this happens automatically when called noninteractively
  -N    =>  do not notify (even if noninteractive)
  
  -x mixer  =>  select mixer ('Master' by default)
  -c card   =>  select card (empty by default)
  
  -h  => display this help and exit
  -V  => display the version and exit

Examples:
  - $script -r      => round volume to multiple of 5
  - $script 10+     => increase volume by 10
  - $script -rn 5-  => decrease volume by 5, round it, and notify-send volume
  - $script -d +    => dynamically increase volume (coming soon)
  - $script -u 40   => unmute and set volume to 40
__EOF

  if [ "${1:-1}" -eq 0 ];
  then
    printf "\nDepends: amixer, perl, sed, notify-send, figlet (opt)\n"
  fi;
  exit "${1:-1}";
}

notify(){
  local vol mutestr icon_name
  vol="$1"
  mutestr="$2"
  if [ -n "$mutestr" ] || [ "$vol" -eq 0 ];
  then
    icon_name="audio-volume-muted";
  elif [ "$vol" -lt 33 ];
  then
    icon_name="audio-volume-low";
  elif [ "$vol" -lt 67 ];
  then
    icon_name="audio-volume-medium";
  else
    icon_name="audio-volume-high";
  fi;
  notify-send "${mutestr:-vol} $vol" \
    -i "$icon_name" \
    -h "int:value:$vol" \
    -h 'string:synchronous:volume';
}

interactive=0;
shouldnotify=0;
if tty -s;
then
  interactive=1;
else
  if xset q >/dev/null 2>&1;
  then
    shouldnotify=1
  fi;
fi;

mixer='Master';
card='';

round=0;
dynamic=0;
mute=0;
unmute=0;
togglemute=0;
verb=1;

while getopts s:x:c:rmutqvnNhVd o;
do
  case "$o" in
    r) round=1             ;;
    d) dynamic=1           ;;
    m) mute=1              ;;
    u) unmute=1            ;;
    t) togglemute=1        ;;
    q) verb=0              ;;
    v) verb=$((verb+1))    ;;
    n) shouldnotify=1      ;;
    N) shouldnotify=0      ;;
    x) mixer="$OPTARG"     ;;
    c) card="$OPTARG"      ;;
    V) echo "vol $version"
       exit 0              ;;
    h) usage 0             ;;
    [?]) usage             ;;
  esac;
done;
shift $((OPTIND-1));

if [ $dynamic -eq 1 ];
then
  echo "Dynamic volume control coming soon ;]";
  exit 42;
fi;

getVol;
debug 2 "initial volume: $vol$mutestr";

volArg="$(echo -n "$*" | sed 's/^\([0-9]\+\)\([+-]\)\(.*\)/\1/')";
incSym="$(echo -n "$*" | sed 's/^\([0-9]\+\)\([+-]\)\(.*\)/\2/')";
restArg="$(echo -n "$*" | sed 's/^\([0-9]\+\)\([+-]\)\(.*\)/\3/')";

if [ "_$restArg" != "_" ];
then
  usage;
fi;

if [ -z "$card" ]
then
  _card="";
else
  _card="-c $card";
fi;

adjusted=0;

# adjust volume
if [ -n "$incSym" ];
then
  # increment volume
  if [ $round -eq 1 ];
  then
    drift=$((2 - ( ( (vol + volArg) % 5 + 2) % 5) ));
    volArg=$((volArg + drift));
  fi;
  amixerVolCmd="$volArg%$incSym"
  debug 2 "incrementing volume by: $incSym$volArg";
elif [ -n "$volArg" ];
then
  # set volume
  if [ $round -eq 1 ];
  then
    drift=$((2 - ( ( (vol + volArg) % 5 + 2) % 5) ));
    volArg=$((volArg + drift));
  fi;
  amixerVolCmd="$volArg%"
  debug 2 "setting volume to: $amixerVolCmd";
elif [ $round -eq 1 ];
then
  drift=$((2 - ( (vol % 5 + 2) % 5) ));
  amixerVolCmd="$((vol + drift))%";
fi;
if [ -n "$amixerVolCmd" ];
then
  debug 3 "\$ amixer set $_card $mixer $amixerVolCmd";
  amixer set $_card "$mixer" "$amixerVolCmd" >/dev/null;
  adjusted=1;
fi;

# muting
if [ $mute -eq 1 ];
then
  amixerMuteCmd=mute;
  debug 2 "muting";
elif [ $unmute -eq 1 ];
then
  amixerMuteCmd=unmute;
  debug 2 "unmuting";
elif [ $togglemute -eq 1 ];
then
  amixerMuteCmd=toggle;
  debug 2 "toggleing mute";
fi;
if [ -n "$amixerMuteCmd" ];
then
  debug 3 "\$ amixer set $_card $mixer $amixerMuteCmd";
  amixer set $_card "$mixer" "$amixerMuteCmd" >/dev/null;
  adjusted=1;
fi;

if [ $adjusted -eq 1 ];
then
  getVol;
fi;

if [ $verb -gt 1 ] || [ $interactive = 1 ] && [ $verb -ne 0 ];
then
  echo "$vol%$mutestr";
fi

if [ $shouldnotify -eq 1 ];
then
  notify "$vol" "$mutestr"
fi;

# vim: ft=sh
📄
ShellCheck Output
If you paste a script in the editor above, this window will show shellcheck output.

ShellCheck is...

A special thanks to the GitHub Sponsors: benliddicottGitpodaniravi24per1234BashSupport Pro per1234WhitewaterFoundryreap2sow1dcminterphotostructureCronitordevholicqmacroani-clicodiga.ioSnapShooter Backups

Wiki Sitemap