strange BASH script behavior

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
17 answers Last reply
More about strange bash script behavior
  1. Liberate that code!

    It wants to be free ;)

    Post or PM me the code so I can try it.
  2. 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.

    [cpp]#! /bin/bash

    # this is my first attempt at making a bash script
    # the purpose of this script is to execute a series of commands that
    # will toggle between metacity and compiz at the touch of a button

    # if the METACITY or COMPIZ variables are equal to either of these two constants
    # then that means that metacity or compiz are currently off

    GREP_CONST_COMPIZ="grep --colour=auto compiz"
    GREP_CONST_METACITY="grep --colour=auto metacity"

    GREP=`ps -ef | grep compiz | cut -c 49- | tail -1`;


    # this variable was also determined experimentally and should be set to
    # the line that actually says whether or not compiz is running

    COMPIZ="`ps -ef | grep compiz | cut -c 49- | head -1`";

    # this variable does the same as the other two, but for metacity

    METACITY="`ps -ef | grep metacity | cut -c 49- | head -1`";


    echo "$GREP"
    echo "$COMPIZ"
    echo "$METACITY"

    exit 0[/cpp]


    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
  3. 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.


    [cpp]#! /bin/bash

    # this is my first attempt at making a bash script
    # the purpose of this script is to execute a series of commands that
    # will toggle between metacity and compiz at the touch of a button

    # if the METACITY or COMPIZ variables are equal to either of these two constants
    # then that means that metacity or compiz are currently off

    METACITY_STATUS="off"
    COMPIZ_STATUS="off"

    #GREP_CONST_COMPIZ="grep --colour=auto compiz"
    #GREP_CONST_METACITY="grep --colour=auto metacity"
    #temporary work around, just remove the --color... :( FIXME

    GREP_CONST_COMPIZ="grep compiz"
    GREP_CONST_METACITY="grep metacity"


    GREP=`ps -ef | grep compiz | cut -c 49- | tail -1`;


    # this variable was also determined experimentally and should be set to
    # the line that actually says whether or not compiz is running

    COMPIZ="`ps -ef | grep compiz | cut -c 49- | head -1`";

    # this variable does the same as the other two, but for metacity

    METACITY="`ps -ef | grep metacity | cut -c 49- | head -1`";

    if [ "$METACITY" == "$GREP_CONST_METACITY" ]; then
    METACITY_STATUS="off"
    else
    METACITY_STATUS="on"
    fi

    if [ "$COMPIZ" == "$GREP_CONST_COMPIZ" ]; then
    COMPIZ_STATUS="off"
    else
    COMPIZ_STATUS="on"
    fi

    if [ "$COMPIZ_STATUS" == "on" -a "$METACITY_STATUS" == "on" ]; then
    metacity --replace &
    killall compiz
    killall emerald
    #if both compiz and metacity are on, default to metacity for safe fallback
    elif [ "$COMPIZ_STATUS" == "on" -a "$METACITY_STATUS" == "off" ]; then
    metacity --replace & #toggle compiz off
    elif [ "$COMPIZ_STATUS" == "off" -a "$METACITY_STATUS" == "on" ]; then
    compiz --replace --loose-binding ccp &
    emerald --replace &
    #toggle compiz on
    else #this should NEVER happen
    echo "SOMETHING IS HORRIBLY WRONG"
    exit -1
    fi



    exit 0[/cpp]

    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
  4. 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 :)
  5. Your cut and tail helps but you may still get funky results :)

    I'll yield to bmouring our resident bash expert :)
  6. 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
  7. 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.
  8. Great suggestions :)

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

    All are good languages to learn.
  9. 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
  10. 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:
  11. Some perl and some regex would do it or shell + ps + awk + grep
  12. ...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
  13. man opendir :)

    better yet

    poor person's ls (TM)

    
    #!/usr/bin/perl
    
    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";
    
    my $mydir=$ARGV[0] or "";
    
    opendir(MYDIR, "$mydir") or die "unable to open $mydir: $!\n" if($mydir ne "");
    
    @myfiles = grep { !/^\./ } readdir(MYDIR);
    closedir DIR;
    
            foreach $file (@myfiles)
            {
            print "$file\n";
            }
    
    



    This program comes with ABSOLUTELY NO WARRANTY
    This is free software, and you are welcome to redistribute it under certain conditions
  14. 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
  15. 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).
  16. Thanks, ijack!

    -Zorak
  17. 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/>. */

    /* 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


    :)
Ask a new question