Sign in with
Sign up | Sign in
Your question

strange BASH script behavior

Last response: in Linux/Free BSD
Share
July 28, 2008 3:40:34 PM

I took a class on using linux a little while ago which included bash scripting, but I haven't done any scripting since then. Today I decided it would be nice if I made a script that I could bind a key to so I could toggle between metacity and compiz to play games. The thing is, I first need to determine which WM is running in the script, so I set up a few variables and set them equal to the output of ps (with some manipulation to get what I needed). So, I wanted to check to see if I was doing everything correctly so i justed echoed back the 3 variables at the bottom. The weird part is that when I echoed the first two, they returned the proper values (with one being not quite right), but then when i echoed all 3 back it printed the same value twice followed by the value of the third variable! Am I missing something here? It is a bit disturbing to see the value of your variables changing depending on the number of echos :( 

If I need to post the script so far to be helpful, let me know and I will. Thanks

-Zorak
July 28, 2008 4:32:59 PM

Liberate that code!

It wants to be free ;) 

Post or PM me the code so I can try it.
July 28, 2008 4:45:32 PM

This is the code I have so far. I've mucked around a little bit with it since i first posted but I haven't made much progress.

  1. #! /bin/bash
  2.  
  3. # this is my first attempt at making a bash script
  4. # the purpose of this script is to execute a series of commands that
  5. # will toggle between metacity and compiz at the touch of a button
  6.  
  7. # if the METACITY or COMPIZ variables are equal to either of these two constants
  8. # then that means that metacity or compiz are currently off
  9.  
  10. GREP_CONST_COMPIZ="grep --colour=auto compiz"
  11. GREP_CONST_METACITY="grep --colour=auto metacity"
  12.  
  13. GREP=`ps -ef | grep compiz | cut -c 49- | tail -1`;
  14.  
  15.  
  16. # this variable was also determined experimentally and should be set to
  17. # the line that actually says whether or not compiz is running
  18.  
  19. COMPIZ="`ps -ef | grep compiz | cut -c 49- | head -1`";
  20.  
  21. # this variable does the same as the other two, but for metacity
  22.  
  23. METACITY="`ps -ef | grep metacity | cut -c 49- | head -1`";
  24.  
  25.  
  26. echo "$GREP"
  27. echo "$COMPIZ"
  28. echo "$METACITY"
  29.  
  30. exit 0



I also noticed that when I run this script, sometimes the output is only two lines, most of the time it is 3 lines, and sometimes the top line displays what it is supposed to and sometimes it displays the same as the second line. the output should read as follows:


grep compiz
compiz --replace --loose-binding ccp
grep metacity


and actually the lines that say grep should include the --colour=auto that normally shows up when I execute the instructions in my script by hand, but when I execute the script it doesn't show those options...

Thanks man

-Zorak
Related resources
July 28, 2008 5:54:15 PM

Well, I think I got my script working. It seems to be able to toggle between the two WMs, but I am still not to sure about that wierd behavior. So, I'd appreciate any input you guys may be willing to provide.


  1. #! /bin/bash
  2.  
  3. # this is my first attempt at making a bash script
  4. # the purpose of this script is to execute a series of commands that
  5. # will toggle between metacity and compiz at the touch of a button
  6.  
  7. # if the METACITY or COMPIZ variables are equal to either of these two constants
  8. # then that means that metacity or compiz are currently off
  9.  
  10. METACITY_STATUS="off"
  11. COMPIZ_STATUS="off"
  12.  
  13. #GREP_CONST_COMPIZ="grep --colour=auto compiz"
  14. #GREP_CONST_METACITY="grep --colour=auto metacity"
  15. #temporary work around, just remove the --color... :( FIXME
  16.  
  17. GREP_CONST_COMPIZ="grep compiz"
  18. GREP_CONST_METACITY="grep metacity"
  19.  
  20.  
  21.  
  22. GREP=`ps -ef | grep compiz | cut -c 49- | tail -1`;
  23.  
  24.  
  25. # this variable was also determined experimentally and should be set to
  26. # the line that actually says whether or not compiz is running
  27.  
  28. COMPIZ="`ps -ef | grep compiz | cut -c 49- | head -1`";
  29.  
  30. # this variable does the same as the other two, but for metacity
  31.  
  32. METACITY="`ps -ef | grep metacity | cut -c 49- | head -1`";
  33.  
  34. if [ "$METACITY" == "$GREP_CONST_METACITY" ]; then
  35. METACITY_STATUS="off"
  36. else
  37. METACITY_STATUS="on"
  38. fi
  39.  
  40. if [ "$COMPIZ" == "$GREP_CONST_COMPIZ" ]; then
  41. COMPIZ_STATUS="off"
  42. else
  43. COMPIZ_STATUS="on"
  44. fi
  45.  
  46. if [ "$COMPIZ_STATUS" == "on" -a "$METACITY_STATUS" == "on" ]; then
  47. metacity --replace &
  48. killall compiz
  49. killall emerald
  50. #if both compiz and metacity are on, default to metacity for safe fallback
  51. elif [ "$COMPIZ_STATUS" == "on" -a "$METACITY_STATUS" == "off" ]; then
  52. metacity --replace & #toggle compiz off
  53. elif [ "$COMPIZ_STATUS" == "off" -a "$METACITY_STATUS" == "on" ]; then
  54. compiz --replace --loose-binding ccp &
  55. emerald --replace &
  56. #toggle compiz on
  57. else #this should NEVER happen
  58. echo "SOMETHING IS HORRIBLY WRONG"
  59. exit -1
  60. fi
  61.  
  62.  
  63.  
  64. exit 0


From here I am gonna bind a key to execute this script using gconf-editor, so if anywould find this script useful, feel free to use it and modify it how you see fit.

-Zorak
July 28, 2008 8:31:27 PM

When you ps |grep you will actually get what you are grepping for along with the grep itself and sometimes if you grep for something that is not unique enough you may get a lot more matches than you might expect so that might be the reason why you are getting strange bahavior.

Try ps |grep $PATTERN |grep -v grep |grep -v $EXCLUDE_PATTERN change $PATTERN and $EXCLUDE_PATTERN accordingly.

GL :) 
July 28, 2008 8:33:11 PM

Your cut and tail helps but you may still get funky results :) 

I'll yield to bmouring our resident bash expert :) 
July 29, 2008 11:45:22 AM

Yeah i know that ps -ef lists EVERYTHING including the piped grep command, which is a behavior I am counting on to determine whether metacity or compiz are running. If $METACITY or $COMPIZ match the $GREP_CONSTANT* that I made that means that the only line that was returned from the process search was the grep, which implies that the corresponding WM, in fact, off. What I don't get is why when I echo back my variables I don't always get the same values (provided that i haven't switched WMs). Also, it is strange that the --colour=auto option doesn't show up in the grep lines that are being stored in variables. It is really strange and I think perhaps I am missing something here.

Anyways, i just found that the way to bind a key to execute that script in GNOME depends on metacity already running in the background; so that means I have to bind that key for metacity and compiz separately. This isn't so bad, but for right now the compiz configuration program seems to be broken so I have to fix that first. This makes me wish there were a way to configure that keybinding in X directly instead of relying on the window manager configurators to bind that key.

I'll probaly look into that later today, but I appreciate any ideas you guys have. Thanks!

-Zorak
August 1, 2008 5:48:57 AM

xbindkeys

It's (likely) just what the doctor ordered, I use it for all of my extra media keys and mouse buttons.

Also, for sanitizing lines, you may want to use awk to run through lines and look for specific tokens that reveal a true, valid line. Or just exclude it as linux_0 suggested.
August 1, 2008 9:21:48 AM

Great suggestions :) 

awk ( man gawk ) is very cool maybe throw in some perl or python.

All are good languages to learn.
August 1, 2008 10:05:04 AM

Haha it never ends! I guess that is kinda a feature I like about computers. It seems like the more I learn, the more I need to learn! The only downside to that is that sometimes I feel like I don't know very much at all in spite of all that I have learned. But I am getting there bit by bit!

-Zorak
August 1, 2008 10:16:32 AM

You could write a C program to run your perl program which in turn will call the shell to run some commands to do what you need to do ;) 

:lol: 
August 1, 2008 10:28:00 AM

Some perl and some regex would do it or shell + ps + awk + grep
August 1, 2008 10:34:41 AM

...yeah or maybe I should just change the microcode in my processor to create a "toggle compiz off/on" instruction in the CPU! ;) 

Seriously though. I know that C and Unix are like newlyweds (i.e. inseparable) -on that note they have been newlyweds for about 40 years... - but I have never seen any examples of how one would do things like traversing directories or checking what processes are running. I am aware that all of these shell commands are all written in C, but they still seem like magic to me at some level. Maybe it is time for me to look at the source code? Hahahaha.

-Zorak
August 1, 2008 10:53:49 AM

man opendir :) 

better yet

poor person's ls (TM)

  1. #!/usr/bin/perl
  2.  
  3. print "\n\n\tpoor person's ls (TM) version 0.0.0.0.0.0.0.0.1 released under the GPL v3\n\n\n\tUsage $0 [dir]\n\n";
  4.  
  5. my $mydir=$ARGV[0] or "";
  6.  
  7. opendir(MYDIR, "$mydir") or die "unable to open $mydir: $!\n" if($mydir ne "");
  8.  
  9. @myfiles = grep { !/^\./ } readdir(MYDIR);
  10. closedir DIR;
  11.  
  12. foreach $file (@myfiles)
  13. {
  14. print "$file\n";
  15. }





This program comes with ABSOLUTELY NO WARRANTY
This is free software, and you are welcome to redistribute it under certain conditions
August 1, 2008 3:18:52 PM

Hahah! You know, i think my favorite disclaimer is the one that says "If this software breaks, you get to keep both pieces" :D 

I think a lot of my curiosity stems from the fact that I like to know HOW things work. I am not satisfied just that they work, which is why I am interested in computer hardware and software. I like understanding all the low level stuff and it gives me an even greater appreciation for the systems that we have in place.

By the way, isn't using perl cheating? ;)  I mean, by the time your perl can be executed you already have a full system in place; with C you wouldn't even need anything besides the hardware. That is to say, you could start of with a rudimentary C compiler made in assembly and bootstrap yourself to a working system whereas you can't do that with interpreted languages.

-Zorak
August 2, 2008 8:09:58 AM

Quote:
but I have never seen any examples of how one would do things like traversing directories or checking what processes are running

Zorak - Have a look at this book. It will tell you everything that you need to know (and quite a few things that you didn't know you needed to know).
August 2, 2008 11:42:50 AM

Thanks, ijack!

-Zorak
August 2, 2008 8:52:57 PM

What the perl code was meant to demonstrate is that fundamentally /bin/ls performs an opendir() system call followed by a readdir() system call.

This is undoubtedly a gross simplification.

It also checks 50 million command line arguments :lol:  among other things.

Perl's opendir() and readdir() are essentially calls to the system's C library which calls the C version of opendir() and readdir()

The perl version is easier to read, write and execute ;) 

Quote:
"gnu/coreutils-6.12/src/ls.c"

static void
print_dir (char const *name, char const *realname, bool command_line_arg)
{
DIR *dirp;
struct dirent *next;
uintmax_t total_blocks = 0;
static bool first = true;

errno = 0;
dirp = opendir (name);
if (!dirp)
{
file_failure (command_line_arg, _("cannot open directory %s"), name);
return;
}

if (LOOP_DETECT)
{
struct stat dir_stat;
int fd = dirfd (dirp);

/* If dirfd failed, endure the overhead of using stat. */
if ((0 <= fd
? fstat (fd, &dir_stat)
: stat (name, &dir_stat)) < 0)
{
file_failure (command_line_arg,
_("cannot determine device and inode of %s"), name);
closedir (dirp);
return;
}

/* If we've already visited this dev/inode pair, warn that
we've found a loop, and do not process this directory. */
if (visit_dir (dir_stat.st_dev, dir_stat.st_ino))
{
error (0, 0, _("%s: not listing already-listed directory"),
quotearg_colon (name));
closedir (dirp);
return;
}

DEV_INO_PUSH (dir_stat.st_dev, dir_stat.st_ino);
}

/* Read the directory entries, and insert the subfiles into the `cwd_file'
table. */

clear_files ();

while (1)
{
/* Set errno to zero so we can distinguish between a readdir failure
and when readdir simply finds that there are no more entries. */
errno = 0;
next = readdir (dirp);
if (next)
{
if (! file_ignored (next->d_name))
{
enum filetype type = unknown;

#if HAVE_STRUCT_DIRENT_D_TYPE
switch (next->d_type)
{
case DT_BLK: type = blockdev; break;
case DT_CHR: type = chardev; break;
case DT_DIR: type = directory; break;
case DT_FIFO: type = fifo; break;
case DT_LNK: type = symbolic_link; break;
case DT_REG: type = normal; break;
case DT_SOCK: type = sock; break;
# ifdef DT_WHT
case DT_WHT: type = whiteout; break;
# endif
}
#endif
total_blocks += gobble_file (next->d_name, type, D_INO (next),
false, name);
}
}
else if (errno != 0)
{
file_failure (command_line_arg, _("reading directory %s"), name);
if (errno != EOVERFLOW)
break;
}
else
break;
}

if (closedir (dirp) != 0)
{
file_failure (command_line_arg, _("closing directory %s"), name);
/* Don't return; print whatever we got. */
}

/* Sort the directory contents. */
sort_files ();

/* If any member files are subdirectories, perhaps they should have their
contents listed rather than being mentioned here as files. */

if (recursive)
extract_dirs_from_files (name, command_line_arg);

if (recursive | print_dir_name)
{
if (!first)
DIRED_PUTCHAR ('\n');
first = false;
DIRED_INDENT ();
PUSH_CURRENT_DIRED_POS (&subdired_obstack);
dired_pos += quote_name (stdout, realname ? realname : name,
dirname_quoting_options, NULL);
PUSH_CURRENT_DIRED_POS (&subdired_obstack);
DIRED_FPUTS_LITERAL (":\n", stdout);
}





Quote:
"gnu/coreutils-6.12/src/ls.c"
/* `dir', `vdir' and `ls' directory listing programs for GNU.
Copyright (C) 85, 88, 90, 91, 1995-2008 Free Software Foundation, Inc.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/&gt;. */

/* If ls_mode is LS_MULTI_COL,
the multi-column format is the default regardless
of the type of output device.
This is for the `dir' program.

If ls_mode is LS_LONG_FORMAT,
the long format is the default regardless of the
type of output device.
This is for the `vdir' program.

If ls_mode is LS_LS,
the output format depends on whether the output
device is a terminal.
This is for the `ls' program. */

/* Written by Richard Stallman and David MacKenzie. */

/* Color support by Peter Anvin <EMAIL REMOVED TO PREVENT SPAM> and Dennis
Flaherty <EMAIL REMOVED TO PREVENT SPAM> based on original patches by
Greg Lee <EMAIL REMOVED TO PREVENT SPAM>. */




EDIT: email addresses were initially obfuscated and subsequently removed to prevent spamming


:) 
!