LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 01-04-2017, 01:55 AM   #1
Southern Gorilla
Member
 
Registered: Dec 2016
Location: Arlington, TX
Distribution: Slackware 14.1
Posts: 66

Rep: Reputation: Disabled
Can't get bash case statement to set variable


Can somebody point out what I'm doing wrong here?
Code:
case ${WClass} in
        "Pale moon"|Gimp|Xfe|PhotoQt)
		Bkg="/solid"
	;;
	*)
		Bkg=""
	;;
esac
I know the ${WClass} is working because I have it echoing after this case statement. But $Bkg never changes regardless whether $WClass matches one of the patterns or not. I've tried putting the set in brackets like I would expect to do in a sed regexp or somewhere. I don't get any errors, just the wrong behavior.
 
Old 01-04-2017, 02:39 AM   #2
Jjanel
Member
 
Registered: Jun 2016
Distribution: any&all, in VBox; Ol'UnixCLI; NO GUI resources
Posts: 999
Blog Entries: 12

Rep: Reputation: 362Reputation: 362Reputation: 362Reputation: 362
Are you looking for/at $Bkg *after* the script exits? (It's 'gone'!)
Put an echo $Bkg as the last line, after the esac, to 'check'.
(I did that, and it 'worked' *inside* that script; but 'not' at shell prompt, after script)

http://serverfault.com/questions/336...ript-execution

Try: source yourscriptname

$ sh z
/solid
$ echo $Bkg

$ source z
/solid
$ echo $Bkg
/solid
$

Is this what is happening in you case?

Best wishes & welcome to LQ!

p.s. Oh, I added as a first line, to test: WClass="Xfe"

(not directly related, but lookup export, for *child* processes to see it)
and getting deeply obscure: http://stackoverflow.com/questions/4...-calling-shell

Last edited by Jjanel; 01-04-2017 at 03:10 AM.
 
Old 01-04-2017, 02:39 AM   #3
xode
Member
 
Registered: Aug 2003
Distribution: Mandrake 9.0; FC4; FC8; SUSE 10.3; SUSE 12.1; SUSE 13.2
Posts: 626
Blog Entries: 1

Rep: Reputation: 50
You had {}'s around $WClass. I tried out the code below and it works. Also, for string constants (e.g. 'Pale moon'), I like single quotes better than double quotes but either should work.

Code:
case $WClass in
        'Pale moon'|Gimp|Xfe|PhotoQt)
		Bkg="/solid"
	;;
	*)
		Bkg=""
	;;
esac
 
Old 01-04-2017, 04:02 AM   #4
Southern Gorilla
Member
 
Registered: Dec 2016
Location: Arlington, TX
Distribution: Slackware 14.1
Posts: 66

Original Poster
Rep: Reputation: Disabled
I made the suggested changes and still had the problem;
Code:
# Function to check if current window needs solid background
check_solids(){
	case $WClass in
		'Pale moon'|Gimp|Xfe|PhotoQt)
			Bkg="/solid"
		;;
		*)
			Bkg=""
		;;
	esac
 echo $WClass	"Bkg="$Bkg
}
And here's the resulting output;
Code:
LilyTerm Bkg=
PhotoQt Bkg=
Bkg=
Pale moon Bkg=
LilyTerm Bkg=
I thought the problem might be because it's inside a function. But the echo is inside the function as well, so that shouldn't matter. All the info I find online says the syntax I have should work, but it doesn't. Oh, that line with the missing WClass output is normal. My text editor doesn't have a window class according to xprop.

Does it matter that this function is called from a while loop? Shouldn't it still echo whatever is inside of the function regardless where it was called from? I apologize if I'm not providing enough information. The last coding I did was in BASIC on an Apple II. So I don't really know what's relevant to the problem. I thought it was just a missing set of brackets or something else with the syntax of the case statement. Obviously, it's getting the WClass information from the function that parses xprop.

I think there's something wrong with my system overall. This is not the only problem I'm having with strange behavior right now. This may be just another symptom of the larger issue.

In case it makes any difference, here's all the functional code from the script. It's all separate functions at the moment because it's easier for me to figure out little bits at a time. I plan to tie it together more cleanly once I grasp what I'm doing;
Code:
# Function to get window info
get_xprop(){
  # This first line converts a command to a variable to reduce verbosity
  Base=$(xprop -root |grep _NET_ACTIVE_WINDOW |head -1 |awk '{print $5}')
  # The next three lines get the desired values and tidy them up a bit.
  IFS=, read WInstance WClass <<<"$(xprop -id $Base WM_CLASS |cut -d "=" -f2 |tr -d '"' |sed 's/^[ \t]*//')"
  WName=$(xprop -id $Base WM_NAME |cut -d "=" -f2 |tr -d '"' |sed 's/^[ \t]*//')
  WRole=$(xprop -id $Base WM_WINDOW_ROLE |cut -d "=" -f2 |cut -d ":" -f2 |tr -d '"' |sed 's/^[ \t]*//')
}

# Function to check for change of focus
compare_focus(){
	get_xprop
	#Concatate info to create a sort of "hash" for comparison
	Conc_new=$(echo $WClass$WInstance$WName$WRole |tr -dC [:alnum:])
	if [ "$Conc_new" != "$Conc_old" ]
		then
		check_solids; Conc_old=$Conc_new
	fi
}

# Function to check if current window needs solid background
check_solids(){
	case $WClass in
		'Pale moon'|Gimp|Xfe|PhotoQt)
			Bkg="/solid"
		;;
		*)
			Bkg=""
		;;
	esac
 echo $WClass	"Bkg="$Bkg
}

# Core code needed to tie the functions together
while true; do
	compare_focus
done
For what it's worth, the script is meant to keep tabs on which workspace I'm on and switch the wallpaper if needed. Some programs are almost illegible with a fancy background bleeding through the reduced opacity. Which seems to be a bug in the compositor, it's supposed to have these windows at 99%. But that's an issue for a different forum. Anyhow, I set out to arrange for these programs to have a solid background. That will go along with a cronjob that changes the background periodically. But that's also beyond the scope of this question.
 
Old 01-04-2017, 05:18 AM   #5
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 9,816

Rep: Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071
So, normally I would just say use the good ole set -xv, however this did not help in this case, so what it was back to not only echoing variables but also including delimiters to make sure what
you have stored

Update to the following and all will be revealed:
Code:
echo "|$WClass|	Bkg=$Bkg"
Also, the addition or removal of {} around the variable names will make no difference. They are generally only required when you need to append something to what is stored in a variable
and you need to tell bash what the variable name is, like:
Code:
echo "start$WClassend"
echo "start${WClass}end"
In the above example the first will only show the string 'start' as you have no variable called 'WClassend', but the second will return all necessary information
 
Old 01-04-2017, 05:56 AM   #6
Southern Gorilla
Member
 
Registered: Dec 2016
Location: Arlington, TX
Distribution: Slackware 14.1
Posts: 66

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by grail View Post
So, normally I would just say use the good ole set -xv, however this did not help in this case, so what it was back to not only echoing variables but also including delimiters to make sure what
you have stored

Update to the following and all will be revealed:
Code:
echo "|$WClass|	Bkg=$Bkg"
I see the problem! Brilliant trick! Sed isn't cutting the leading spaces!
Code:
| LilyTerm|	Bkg=
| PhotoQt|	Bkg=
| |	Bkg=
| Pale moon|	Bkg=
| LilyTerm|	Bkg=
I still had a bit of confusion because the problem wasn't exactly where I thought it was. I had to change things up a bit, add a new variable to the read command and then echo that through sed to get rid of the offending spaces. Why doesn't the sed at the end of the 'read' line do the trick? And what can I do to make this less, um... hack? There's got to be a better way than echoing one variable into another. I know it's silly trying to polish this turd when I'm sure there are people lurking with 17 different ways to do the whole thing better. But I have to learn somehow.
Code:
get_xprop(){
  # This first line converts a command to a variable to reduce verbosity
  Base=$(xprop -root |grep _NET_ACTIVE_WINDOW |head -1 |awk '{print $5}')
  # The next three lines get the desired values and tidy them up a bit.
  IFS=, read WInstance no_class <<<"$(xprop -id $Base WM_CLASS |cut -d "=" -f2 |tr -d '"' |sed 's/^[[:space:]]*//')"
  WClass=$(echo $no_class |sed 's/^[[:space:]]*//')
  WName=$(xprop -id $Base WM_NAME |cut -d "=" -f2 |tr -d '"' |sed 's/^[[:space:]]*//')
  WRole=$(xprop -id $Base WM_WINDOW_ROLE |cut -d "=" -f2 |cut -d ":" -f2 |tr -d '"' |sed 's/^[[:space:]]*//')
}
At any rate, I now get the expected result. And I also learned something new. Just in time to go to bed.
Code:
|LilyTerm|	Bkg=
|PhotoQt|	Bkg=/solid
||	Bkg=
|Pale moon|	Bkg=/solid
|LilyTerm|	Bkg=
 
Old 01-04-2017, 06:51 AM   #7
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 9,816

Rep: Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071
This works for me:
Code:
base=$(xprop -root | awk '/^_NET_ACTIVE_WINDOW/{print $NF}')

IFS=',"' read _ WInstance _ _ WClass <<<$(xprop -id $base WM_CLASS)
#OR
IFS=, read WInstance WClass <<<$(xprop -id $base WM_CLASS | awk -F\" '{print $2","$4}')

WName=$(xprop -id $base WM_NAME | awk -F\" '{print $(NF-1)}')
 
1 members found this post helpful.
Old 01-04-2017, 07:08 AM   #8
Southern Gorilla
Member
 
Registered: Dec 2016
Location: Arlington, TX
Distribution: Slackware 14.1
Posts: 66

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by grail View Post
This works for me:
Code:
base=$(xprop -root | awk '/^_NET_ACTIVE_WINDOW/{print $NF}')

IFS=',"' read _ WInstance _ _ WClass <<<$(xprop -id $base WM_CLASS)
#OR
IFS=, read WInstance WClass <<<$(xprop -id $base WM_CLASS | awk -F\" '{print $2","$4}')

WName=$(xprop -id $base WM_NAME | awk -F\" '{print $(NF-1)}')
That is so much prettier than what I had. I really need to explore awk more. I'll have to spend some time studying that so I can understand exactly what's going on. Those two variations of the read command are so wildly different from each other, and from what I had. It really shows there are a great many things I don't know yet. Thanks for taking the time to share that. Of course, I'm not sure I could bear to write three whole lines of code without using sed for something. I might have withdrawal.
 
Old 01-04-2017, 08:00 AM   #9
gnashley
Amigo developer
 
Registered: Dec 2003
Location: Germany
Distribution: Slackware
Posts: 4,902

Rep: Reputation: 590Reputation: 590Reputation: 590Reputation: 590Reputation: 590Reputation: 590
No need, really, for all the mawking about with grep/sed/tr/cut/awk!
Code:
#!/bin/bash

set -- $(xprop -root)
base=$5

#set $(xprop -id $base WM_CLASS)
#echo WM_CLASS=${4//\"/}

set $(xprop -id $base WM_NAME)
echo WM_NAME=${3//\"/}
set $(xprop -id $base WM_WINDOW_ROLE)
echo WM_WINDOW_ROLE=$2 $3
# or:
#echo $2 ${3/\./}
My active window (manager) doesn't seem to support WINDOW_ROLE, so I'm not sure what a hit looks like -you may need to change the last line or two.
 
1 members found this post helpful.
Old 01-04-2017, 08:05 AM   #10
Southern Gorilla
Member
 
Registered: Dec 2016
Location: Arlington, TX
Distribution: Slackware 14.1
Posts: 66

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by gnashley View Post
No need, really, for all the mawking about with grep/sed/tr/cut/awk!
Code:
#!/bin/bash

set -- $(xprop -root)
base=$5

#set $(xprop -id $base WM_CLASS)
#echo WM_CLASS=${4//\"/}

set $(xprop -id $base WM_NAME)
echo WM_NAME=${3//\"/}
set $(xprop -id $base WM_WINDOW_ROLE)
echo WM_WINDOW_ROLE=$2 $3
# or:
#echo $2 ${3/\./}
My active window (manager) doesn't seem to support WINDOW_ROLE, so I'm not sure what a hit looks like -you may need to change the last line or two.
I don't have a clue how all that works. I'll definitely be studying it. Thank you very much for sharing it.

*EDIT*
WINDOW_ROLE seems to be the most commonly ignored hint. But as you can see in the output I pasted above, even window class can be ignored by some programs. That's why I gathered every bit of information my WM recognizes.

Last edited by Southern Gorilla; 01-04-2017 at 08:07 AM. Reason: Forgot to mention...
 
Old 01-04-2017, 12:06 PM   #11
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 9,816

Rep: Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071
You would need to go over the data as $5 is not the same 'base' value for me, seeing xprop -root gives a whole screen of data.

As to what is going on, the 'set' command is setting the positional variables 1 to N as if you passed all the arguments to a script and then you reference them by number, 2, 3, 4 & 5 in the example provided.

For me the base is the 13th value and here you would again need to use {} to keep the numbers grouped together, ie. ${13}, but gnashley is quite correct that parameter substitution is another good option
to stay all in bash without punching out to other commands
 
Old 01-04-2017, 05:38 PM   #12
Southern Gorilla
Member
 
Registered: Dec 2016
Location: Arlington, TX
Distribution: Slackware 14.1
Posts: 66

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by grail View Post
You would need to go over the data as $5 is not the same 'base' value for me, seeing xprop -root gives a whole screen of data.

As to what is going on, the 'set' command is setting the positional variables 1 to N as if you passed all the arguments to a script and then you reference them by number, 2, 3, 4 & 5 in the example provided.

For me the base is the 13th value and here you would again need to use {} to keep the numbers grouped together, ie. ${13}, but gnashley is quite correct that parameter substitution is another good option
to stay all in bash without punching out to other commands
It looks like 'grep' is still useful in this application. Xprop returns a bunch of lines and gnashley's code pulls in the first id#, which is not the right one. Using 'grep' to get the correct line would be a lot simpler than trying to cipher the value of the correct id# at the end of the 7th line. Actually, I don't think you could calculate that value consistently. Changing any of the intermediate parameters would change the value of the one you were after.
Code:
_XROOTPMAP_ID(PIXMAP): pixmap id # 0x1c00001
_NET_CURRENT_DESKTOP(CARDINAL) = 4
I3_SHMLOG_PATH(UTF8_STRING) = 
I3_CONFIG_PATH(UTF8_STRING) = "/home/neanderthal/.i3/config"
I3_PID(CARDINAL) = 1274
I3_SOCKET_PATH(UTF8_STRING) = "/tmp/i3-neanderthal.eCtd0X/ipc-socket.1274"
_NET_ACTIVE_WINDOW(WINDOW): window id # 0x120012d
And it apparently collapses spaces inside quotes. Which complicates matters somewhat. There's a big difference between what 'xprop' kicks out and what that pretty code returns.
Code:
$ set $(xprop -id $base WM_NAME)
$ echo WM_NAME=${3//\"/}
WM_NAME=/home/neanderthal/Build

$ xprop -id $base WM_NAME
WM_NAME(STRING) = "/home/neanderthal/Build - LilyTerm"
That's the tricky bit about coding though, isn't it? Trying to find one procedure that safely turns all possible input into the correct output. The reason my original code was so convoluted was because I had tested those lines dozens of times to figure out how to grab exactly what I needed from what I was given. And I'm still missing stuff. But parameter substitution is my new Favorite Thing. Now that I've gotten a taste of what it can do I'll be working it into the rest of my script where I can. And I'll be delving deeper into what bash has to offer. I want to see where its limits really are.
 
Old 01-05-2017, 01:33 AM   #13
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 9,816

Rep: Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071Reputation: 3071
Glad you are getting into the joys of bash Just in case you do not already have it, the link below is one I fully recommend reading through as time permits:

http://mywiki.wooledge.org/TitleIndex
 
Old 01-05-2017, 02:04 AM   #14
Southern Gorilla
Member
 
Registered: Dec 2016
Location: Arlington, TX
Distribution: Slackware 14.1
Posts: 66

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by grail View Post
Glad you are getting into the joys of bash Just in case you do not already have it, the link below is one I fully recommend reading through as time permits:

http://mywiki.wooledge.org/TitleIndex
Wow! That's a whole lot of information. I should have a degree in bash by the time I finish reading all that.

Honestly, I started learning bash because it's always there and I'm always needing to do something trivial with it. I was starting to believe the folks who were telling me that bash is just a phase and I'll grow out of it and start looking for a "real" programming language. But this thread has really opened my eyes. I thought I was getting close to competent. Now I see I haven't even scratched the surface. Yes, I'm excited to see where I can go now that I know there's much more to explore than I had imagined. This is far from a "basic" language.

I did want to ask, what is the purpose of the underscores in this line?
Code:
IFS=',"' read _ WInstance _ _ WClass <<<$(xprop -id $base WM_CLASS)

Last edited by Southern Gorilla; 01-05-2017 at 02:08 AM. Reason: Forgot a question
 
Old 01-05-2017, 02:26 AM   #15
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=14, FreeBSD_12{.0|.1}
Posts: 5,583
Blog Entries: 11

Rep: Reputation: 3602Reputation: 3602Reputation: 3602Reputation: 3602Reputation: 3602Reputation: 3602Reputation: 3602Reputation: 3602Reputation: 3602Reputation: 3602Reputation: 3602
And don't ignore the bash man page - a terrific resource!

Although certainly not tutorial in style, it is actually very readable, accessible and complete - a treasure among man pages!

I think a common obstacle for many is simply its length and unfamiliarity. So learn how it is organized and how to navigate quickly to major topics. Read it, one digestible section at a time to gain comfortable familiarity over time. You will be glad you did!
 
1 members found this post helpful.
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Perl switch statement throwing error like Bad case statement (invalid case value?) kavil Programming 2 10-07-2010 04:50 AM
BASH - regex in a case statement akelder Programming 3 06-09-2010 04:02 PM
escape '*' in case statement bash junust Programming 2 01-23-2010 03:54 AM
[SOLVED] BASH --> esc key in a case statement manwithaplan Linux - Newbie 6 10-05-2009 10:33 PM
bash'ed by case statement??? 3inone Programming 2 04-29-2004 04:52 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 08:01 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration