You are not logged in.

#1 2016-04-02 09:29:24

RankoKohime
Member
Registered: 2014-01-08
Posts: 87
Website

[SOLVED] Working with variables in shell scripting

I run Awesome as my WM, and I've created a script for managing my audio devices with shortcut keys.

I'm running into a small annoyance, however, in that the reported volume lags behind the actual volume.  The script changes the volume of my speakers in 5% increments, however the reported volume (via notify-send) is the volume BEFORE the change.  So obviously the variable contents (of SPK_VOL specifically) are being executed before the function that it's called from.  And now that I think about it, the same could be said of IS_MUTED_SPK and IS_MUTED_MIC, as I have to reverse their readings in the later if statement.

I can force it to work correctly by moving the variable into the respective function, after the line where the volume is changed, but this results in code duplication, and I think there has to be a cleaner way of doing it than that.

#!/bin/bash
set +x
#trap read debug
 
# Interfaces
MIC_FACE="alsa_input.pci-0000_00_1b.0.analog-stereo"
#SPK_FACE="alsa_output.pci-0000_01_00.1.hdmi-stereo-extra1"  # PG279Q
SPK_FACE="alsa_output.pci-0000_01_00.1.hdmi-stereo-extra2"  # B326HK
 
# Functions
MUTE_MIC() ( pactl set-source-mute $MIC_FACE toggle;
                if [ $IS_MUTED_MIC = no ]
                  then
                    notify-send "Microphone" "Muted"
                  else
                    notify-send "Microphone" "Unmuted"
                fi )
FIX_MIC()  ( pactl set-source-volume $MIC_FACE 6554;
             notify-send "Microphone" "Volume set to $VOL_MIC" )
LOWR_SPK() ( pactl set-sink-volume $SPK_FACE -5%;
             sleep 0.5;
             notify-send "Monitor Speakers" "Volume set to $VOL_SPK" )
RISE_SPK() ( pactl set-sink-volume $SPK_FACE +5%;
             notify-send "Monitor Speakers" "Volume set to $VOL_SPK" )
MUTE_SPK() ( pactl set-sink-mute $SPK_FACE toggle;
                if [ $IS_MUTED_SPK = no ]
                  then
                    notify-send "Monitor Speakers" "MUTED"
                  else
                    notify-send "Monitor Speakers" "UNMUTED"
                fi )
 
# Mute tests
# grep -A 6 $***_FACE
IS_MUTED_MIC=`pactl list sources|sed -n '/'$MIC_FACE'/,/Mute/p' -|grep Mute|awk '{print $2}' -`
IS_MUTED_SPK=`pactl list sinks|sed -n '/'$SPK_FACE'/,/Mute/p' -|head -10|grep Mute|awk '{print $2}' -`
 
# Volume tests
VOL_MIC=`pactl list sources|sed -n '/'$MIC_FACE'/,/Base Volume/p' -|grep "Base Volume"|awk '{print $5}' -`
VOL_SPK=`pactl list sinks|sed -n '/'$SPK_FACE'/,/Base Volume/p' -|grep -m1 "Volume"|awk '{print $5}' -`
 
# Process input commands
case $1 in
        micmute)MUTE_MIC;;
        miclkvl)FIX_MIC;;
        spkmute)MUTE_SPK;;
        spkvlup)RISE_SPK;;
        spkvldn)LOWR_SPK;;
              *)echo "No valid command specified";
                notify-send "Audio Control: Error" "No valid command specified";;
esac

Last edited by RankoKohime (2016-04-10 04:26:55)

Offline

#2 2016-04-02 11:25:52

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,532
Website

Re: [SOLVED] Working with variables in shell scripting

RankoKohime wrote:

So obviously the variable contents (of SPK_VOL specifically) are being executed before the function that it's called from.

Yes, they are.  That's how variables work.  VOL_SPK for example is set only once on line 40.  When the script is run, all the functions are read (but not executed) the variables are set (around line 40) then you call a function and use the values previously asigned to the variable.

What it looks like you want to do is save that command line on line 40 to a vaiable, then "eval" that variable.  This would work - though there is a much better approach - but as an example, the following would do what you intended:

RISE_SPK() {
   pactl set-sink-volume $SPK_FACE +5%;
   notify-send "Monitor Speakers" "Volume set to $(eval $VOL_SPK)" 
}
...
VOL_SPK="pactl list sinks|sed -n '/'$SPK_FACE'/,/Base Volume/p' -|grep -m1 "Volume"|awk '{print $5}' -"
...

although some escaping would likely need to be done to the quotes on the VOL_SPK variable.  I have not tested this specific code as this really isn't the best way to do this.  It's better to use another function:

VOL_SPK() { pactl list sinks|sed -n '/'$SPK_FACE'/,/Base Volume/p' -|grep -m1 "Volume"|awk '{print $5}' - }
RISE_SPK() {
   pactl set-sink-volume $SPK_FACE +5%;
   notify-send "Monitor Speakers" "Volume set to $(VOL_SPK)" 
}

There are also many other approaches - look around at the scripting threads, many people have written efficient volume control scripts.

Also, sed + grep + awk = awk.  I don't have pactl to test, but that command line on line 40 should be equivalent to the following:

pactl list sinks | awk '/'$SPK_FACE'/{while (!match($0,"Base Volume")) getline; print $5; exit;}'

"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#3 2016-04-03 00:38:39

RankoKohime
Member
Registered: 2014-01-08
Posts: 87
Website

Re: [SOLVED] Working with variables in shell scripting

Trilby wrote:

There are also many other approaches - look around at the scripting threads, many people have written efficient volume control scripts.

Also, sed + grep + awk = awk.  I don't have pactl to test, but that command line on line 40 should be equivalent to the following:

pactl list sinks | awk '/'$SPK_FACE'/{while (!match($0,"Base Volume")) getline; print $5; exit;}'

This has definitely given me a few ideas, and some insight into awk, (which I still haven't studied up on nearly as much I'd like, apparently), however, notify-send being the picky little prat it is, doesn't pick up on either the function call, or the eval.  It doesn't give an error, either, it just ignores it entirely.

Last edited by RankoKohime (2016-04-03 00:39:22)

Offline

#4 2016-04-03 00:49:26

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,532
Website

Re: [SOLVED] Working with variables in shell scripting

notify-send can be as picky as it wants, it has no influence on this.  Notify-send doesn't interpet those variables, the shell does.  It notify send isn't showing anything there then something is wrong elsewhere.  You can replace the notify send command with "echo" and just run the script from the command line for some testing.

I'd do some testing, but I don't use pulse-audio.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#5 2016-04-04 05:42:40

RankoKohime
Member
Registered: 2014-01-08
Posts: 87
Website

Re: [SOLVED] Working with variables in shell scripting

Trilby wrote:

notify-send can be as picky as it wants, it has no influence on this.  Notify-send doesn't interpet those variables, the shell does.  It notify send isn't showing anything there then something is wrong elsewhere.  You can replace the notify send command with "echo" and just run the script from the command line for some testing.

I'd do some testing, but I don't use pulse-audio.

Well, it picks up the variable, $SPK_VOL, but doesn't pick up the function call, $(SPK_VOL) or the eval $(eval $SPK_VOL).  It simply doesn't output anything where the percentage should be.

I've tested to make sure the variable/function does give output, and it does, both before (with sed|grep|awk) and after (just awk).

Last edited by RankoKohime (2016-04-04 05:51:23)

Offline

#6 2016-04-04 11:50:08

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,532
Website

Re: [SOLVED] Working with variables in shell scripting

You could try something like this with the function then:

RISE_SPK() {
   pactl set-sink-volume $SPK_FACE +5%;
   VOL="$(VOL_SPK)"
   echo $VOL
   notify-send "Monitor Speakers" "Volume set to $VOL" 
}

The echo $VOL is there just to test whether VOL is actually set to anything.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#7 2016-04-11 06:49:07

RankoKohime
Member
Registered: 2014-01-08
Posts: 87
Website

Re: [SOLVED] Working with variables in shell scripting

Trilby wrote:

You could try something like this with the function then:

RISE_SPK() {
   pactl set-sink-volume $SPK_FACE +5%;
   VOL="$(VOL_SPK)"
   echo $VOL
   notify-send "Monitor Speakers" "Volume set to $VOL" 
}

The echo $VOL is there just to test whether VOL is actually set to anything.

Several rounds of editing later, and after incorporating the change you mentioned, I've got my script working.  smile

#!/bin/bash
set +x
#trap read debug

# v 1.0, built for yggdrasil-3

# This script handles a variety of different audio configurations, as requested by the window manager (Awesome)


# Interfaces

#     These functions should automatically adjust the interface variable if the interface changes.
#     This is especially a problem with SPK_FACE is it will change when the monitor is swapped.

MIC_FACE=alsa_input.pci-0000_00_1b.0.`pactl list cards|awk -F ":" '/alsa_card.pci-0000_00_1b.0/{while (!match($0,"Active Profile")) getline;print $4;exit;}'`
SPK_FACE=alsa_output.pci-0000_01_00.1.`pactl list cards|awk -F ":" '/alsa_card.pci-0000_01_00.1/{while (!match($0,"Active Profile")) getline;print $3;exit;}'`

# Functions
MUTE_MIC()
(
  pactl set-source-mute $MIC_FACE toggle;
  if [ $IS_MUTED_MIC = no ]
    then
      notify-send "Microphone" "Is Muted"
    else
      notify-send "Microphone" "Is Unmuted"
  fi
)

FIX_MIC()
(
  pactl set-source-volume $MIC_FACE 6554;
  notify-send "Microphone" "Volume set to $(VOL_MIC)"
)

SWAP_SPK()
(
  pactl # In progress
  notify-send "Monitor Speakers" "Switched output to: $SPK_FACE"
)

LOWR_SPK()
(
  pactl set-sink-volume $SPK_FACE -5%;
  notify-send "Monitor Speakers" "Volume set to $(VOL_SPK)"
)

RISE_SPK()
(
  pactl set-sink-volume $SPK_FACE +5%;
  notify-send "Monitor Speakers" "Volume set to $(VOL_SPK)"
)

MUTE_SPK()
(
  pactl set-sink-mute $SPK_FACE toggle;
  if [ $IS_MUTED_SPK = no ]
    then
      notify-send "Monitor Speakers" "MUTED"
    else
      notify-send "Monitor Speakers" "UNMUTED"
  fi
)


# Mute tests
IS_MUTED_MIC=`pactl list sources|awk '/'$MIC_FACE'/{while (!match($0,"Mute")) getline;print $2;exit;}'`
IS_MUTED_SPK=`pactl list sinks|awk '/'$SPK_FACE'/{while (!match($0,"Mute")) getline;print $2;exit;}'`

# Volume tests
VOL_MIC()
(
  pactl list sources|awk '/'$MIC_FACE'/{while (!match($0,"Volume")) getline; print $5; exit; }'
)

VOL_SPK()
(
  pactl list sinks|awk '/'$SPK_FACE'/{while (!match($0,"Volume")) getline; print $5; exit; }'
)

# Process input commands
case $1 in
        micmute)MUTE_MIC;;
        miclkvl)FIX_MIC;;
        spkmute)MUTE_SPK;;
        spkvlup)RISE_SPK;;
        spkvldn)LOWR_SPK;;
        spkswap)SWAP_SPK;;
              *)echo "No valid command specified";
                notify-send "Audio Control: Error" "No valid command specified";;
esac

Offline

Board footer

Powered by FluxBB