UNIX shell scripts - assigning result of command to a variable

Special K

Diamond Member
Jun 18, 2000
7,098
0
76
I am trying to write a check in my .cshrc file to see if an X server is running or not. Basically, I only want to run the command that starts the X server if an X server is not already running, because otherwise I get an annoying error message every time I open a new console and it tries to start an X server when one is already running.

My idea is to grep the list of running processes for the existence of the X server process, and if a match is found, then don't run the command to start the X server. Here is what I have:

set myvar = 'ps -ef | grep /usr/X11R6/bin/XWin'

I tried running the command at the console and it correctly returned a single line of text that corresponded to the X server process. The problem is that when I try assigning it to a variable, as I have shown above, the value of myvar only gets the value of ps -ef; it is completely ignoring the pipe and the grep command. How can I get it to recognize the pipe and the grep command, so that myvar ends up with the single line of text corresponding to the X server process (assuming it is running)?

I tried enclosing the command in backticks, but then myvar only captures the UID of the process, not the entire line. In addition, it then apparently tries to execute the UID as a command, because I then get the error message "Administ: Command not found." How can I make this work? I am using csh under cygwin.
 

CTho9305

Elite Member
Jul 26, 2000
9,214
1
81
Would it work to just check whether or not $DISPLAY is set? Also, I'm not sure if this is useful, but I think grep has a "-c" option which will just tell you whether or not there were any matching lines via its return code.
 

Special K

Diamond Member
Jun 18, 2000
7,098
0
76
Originally posted by: CTho9305
Would it work to just check whether or not $DISPLAY is set? Also, I'm not sure if this is useful, but I think grep has a "-c" option which will just tell you whether or not there were any matching lines via its return code.

I am running rxvt, which is a UNIX-like terminal program that comes with cygwin. By default, cygwin will use the windows cmd terminal, so I prefer to use one that looks and behaves like a real UNIX terminal. Anyway, in some documentation for rxvt I found (see link below), it says:

"If you've installed the rxvt package, you can run it from Windows without having a full X-server running, as long as you don't have a DISPLAY variable set in your environment."

link

so I hadn't been setting my DISPLAY variable. However, I just tried setting it anyway and rxvt still works. I guess I could now check to see whether or not DISPLAY has been set, but if DISPLAY was never set, then how was I able to use X programs before? I was using this windows batch file to bring up rxvt:

@echo off
REM place in C:\cygwin\rxvt.bat and put
REM a shortcut on the desktop :)
c:\cygwin\bin\rxvt -e /bin/tcsh -l

and I have this line in my .cshrc to start the xwindows server:

XWin -multiwindow -ac -clipboard >& /dev/null &

So how does the X server know where to put the windows in this case? Don't you have to give it a line like the following:

setenv DISPLAY 192.168.1.100:0.0

Also, you were correct about grep - the -c flag causes grep to return the number of lines matched, which would also work, if I could only get the command I posted in my first post above to work correctly.
 

QED

Diamond Member
Dec 16, 2005
3,428
3
0
At first glance, the command you used should work just fine. However, when pasting it into my shell here at work, I notice extra spaces before and after the equals sign (not sure if that's just Fusetalk messing up what you typed), which would cause the assignment shell variable assignment to fail. You also should put the command in backticks, or in a "$(command)" form.

This command runs fine on my system:

myvar=`ps -ef | grep /usr/X11R6/bin/Xwin`

Note that "fine" doesn't necessarily mean "as intended". Anytime you look at the process table and look for a matching string via grep, you will
almost certainly find at least one matching line-- namely, the grep process will match itself since it appears in the process table and
contains the string you are looking for. You must filter out the grep command from your results like so:

myvar=`ps -ef | grep /usr/X11R6/bin/Xwin| grep -v grep`

However, maybe your system has a "pidof" command, which simply returns the pids of a process specified on the command line:

myvar=`pidof Xwin`

You can also run the check directly in your script instead of first asigning it to a varialble:

if [[ -z `pidof Xwin' ]]; then Xwin;fi

-or, a bit more succintly-

if ! pidof Xwin >/dev/null 2>&1; then Xwin;fi

-or, if "pidof" is not available-

if ( ps -ef | grep XWin | grep -qv grep ); then XWin; fi

This checks for a process called Xwin, and if it doesn't exist, runs Xwin.

 

Special K

Diamond Member
Jun 18, 2000
7,098
0
76
Originally posted by: QED


However, maybe your system has a "pidof" command, which simply returns the pids of a process specified on the command line:

Cygwin apparently doesn't have the pidof command, so I tried your next option.


Originally posted by: QED
-or, if "pidof" is not available-

if ( ps -ef | grep XWin | grep -qv grep ); then XWin; fi

This checks for a process called Xwin, and if it doesn't exist, runs Xwin.

First of all, why are you using the -q flag with grep here? It doesn't return anything when the -q flag is used. What exactly is it returning in this case that can be checked by the shell script to verify if the Xwin program is running?

Also, I am not sure I understand your syntax. What is the difference between using if/fi and if/endif? Does it depend what shell you are using? I am using csh.

Here is what I currently have:

if ( ps -ef | grep /usr/X11R6/bin/XWin | grep -v grep ) then
XWin -multiwindow -ac -clipboard >& /dev/null &
endif

and it says "if: Expression Syntax" when I try to source it. It also gives me the exact same error message when I copy and paste your version into my .cshrc file.

 

QED

Diamond Member
Dec 16, 2005
3,428
3
0
Originally posted by: Special K
Originally posted by: QED


However, maybe your system has a "pidof" command, which simply returns the pids of a process specified on the command line:

Cygwin apparently doesn't have the pidof command, so I tried your next option.


Originally posted by: QED
-or, if "pidof" is not available-

if ( ps -ef | grep XWin | grep -qv grep ); then XWin; fi

This checks for a process called Xwin, and if it doesn't exist, runs Xwin.

First of all, why are you using the -q flag with grep here? It doesn't return anything when the -q flag is used. What exactly is it returning in this case that can be checked by the shell script to verify if the Xwin program is running?

The -q flag tells grep to be quiet (i.e. it doesn't actually output the matching lines). The grep program will exit with a return code of 0 if it finds a match, and 1 otherwise. In ksh and bash, the "if" statement takes a command (as opposed to csh, which takes a logical expression), executes it, and runs the "then" portion if the command returns with a zero exit value.

Also, I am not sure I understand your syntax. What is the difference between using if/fi and if/endif? Does it depend what shell you are using? I am using csh.

Yep, that's your problem. I don't use csh that much, and everytime I do I remember why I don't.

You're right: csh used if/endif instead of if/fi. Like I said earlier, csh doesn't take a command as the first argument for the "if" statement like bash and ksh do-- which means you have to already have your script set an environment variable with the count.

I would avoid csh, but that's just me. If you can't avoid it, try this (not tested):

if ( `ps -ef | grep XWin | grep -v grep | wc -l` = 0 )
then
XWin
endif



Here is what I currently have:

if ( ps -ef | grep /usr/X11R6/bin/XWin | grep -v grep ) then
XWin -multiwindow -ac -clipboard >& /dev/null &
endif

and it says "if: Expression Syntax" when I try to source it. It also gives me the exact same eror message when I copy and paste your version into my .cshrc file.

[/quote]

 

Special K

Diamond Member
Jun 18, 2000
7,098
0
76
Originally posted by: QED

I would avoid csh, but that's just me. If you can't avoid it, try this (not tested):

if ( `ps -ef | grep XWin | grep -v grep | wc -l` = 0 )
then
XWin
endif

Alright, here is what I have now:

if (`ps -ef | grep /usr/X11R6/bin/XWin | grep -v grep | wc -l` == 0) then

XWin -multiwindow -ac -clipboard >& /dev/null &
endif

This works exactly as it is supposed to. Note that the word 'then' must appear on the same line as the if statement. Some languages don't seem to care much about whitespace but the csh scripts apparently do.

In the example above, why did you decide to pipe the grep result into wc instead of using the -q flag? Would either option have worked?

 

QED

Diamond Member
Dec 16, 2005
3,428
3
0
Originally posted by: Special K
Originally posted by: QED

I would avoid csh, but that's just me. If you can't avoid it, try this (not tested):

if ( `ps -ef | grep XWin | grep -v grep | wc -l` = 0 )
then
XWin
endif

Alright, here is what I have now:

if (`ps -ef | grep /usr/X11R6/bin/XWin | grep -v grep | wc -l` == 0) then

XWin -multiwindow -ac -clipboard >& /dev/null &
endif

This works exactly as it is supposed to. Note that the word 'then' must appear on the same line as the if statement. Some languages don't seem to care much about whitespace but the csh scripts apparently do.

In the example above, why did you decide to pipe the grep result into wc instead of using the -q flag? Would either option have worked?

I needed to use "wc" since csh actually needs a number to be returned in the expression to compare with 0. As you probably know, "wc -l" simply returns a count of the number of lines it is fed-- in this case, this will be the number of matching processes.

For bash and ksh, I don't need a count for the if statement-- I only need to know if a match was found or not, and the grep -q statement will tell me this.
 

Special K

Diamond Member
Jun 18, 2000
7,098
0
76
Originally posted by: QED
Originally posted by: Special K
Originally posted by: QED

I would avoid csh, but that's just me. If you can't avoid it, try this (not tested):

if ( `ps -ef | grep XWin | grep -v grep | wc -l` = 0 )
then
XWin
endif

Alright, here is what I have now:

if (`ps -ef | grep /usr/X11R6/bin/XWin | grep -v grep | wc -l` == 0) then

XWin -multiwindow -ac -clipboard >& /dev/null &
endif

This works exactly as it is supposed to. Note that the word 'then' must appear on the same line as the if statement. Some languages don't seem to care much about whitespace but the csh scripts apparently do.

In the example above, why did you decide to pipe the grep result into wc instead of using the -q flag? Would either option have worked?

I needed to use "wc" since csh actually needs a number to be returned in the expression to compare with 0. As you probably know, "wc -l" simply returns a count of the number of lines it is fed-- in this case, this will be the number of matching processes.

For bash and ksh, I don't need a count for the if statement-- I only need to know if a match was found or not, and the grep -q statement will tell me this.

Earlier you said:

Originally posted by: QED
The -q flag tells grep to be quiet (i.e. it doesn't actually output the matching lines). The grep program will exit with a return code of 0 if it finds a match, and 1 otherwise.

Doesn't that mean that grep -q returns a numerical value (0 or 1) that I can test against in my 'if' statement?
 

QED

Diamond Member
Dec 16, 2005
3,428
3
0
Originally posted by: Special K
Originally posted by: QED
Originally posted by: Special K
Originally posted by: QED

I would avoid csh, but that's just me. If you can't avoid it, try this (not tested):

if ( `ps -ef | grep XWin | grep -v grep | wc -l` = 0 )
then
XWin
endif

Alright, here is what I have now:

if (`ps -ef | grep /usr/X11R6/bin/XWin | grep -v grep | wc -l` == 0) then

XWin -multiwindow -ac -clipboard >& /dev/null &
endif

This works exactly as it is supposed to. Note that the word 'then' must appear on the same line as the if statement. Some languages don't seem to care much about whitespace but the csh scripts apparently do.

In the example above, why did you decide to pipe the grep result into wc instead of using the -q flag? Would either option have worked?

I needed to use "wc" since csh actually needs a number to be returned in the expression to compare with 0. As you probably know, "wc -l" simply returns a count of the number of lines it is fed-- in this case, this will be the number of matching processes.

For bash and ksh, I don't need a count for the if statement-- I only need to know if a match was found or not, and the grep -q statement will tell me this.

Earlier you said:

Originally posted by: QED
The -q flag tells grep to be quiet (i.e. it doesn't actually output the matching lines). The grep program will exit with a return code of 0 if it finds a match, and 1 otherwise.

Doesn't that mean that grep -q returns a numerical value (0 or 1) that I can test against in my 'if' statement?

No. "grep -q" won't actually spit anything to standard output. It will exit silently with a return code of 0 or 1 (or some other non-zero value). The return code is the value passed back to the shell, but you don't see it. The "if" statement in the bash and ksh can see this hidden return value, even though it is not actually spit out to the screen. You can, though, explicity check it yourself or print it out yourself as it will be stored in the special $? environment variable.

The csh version of if requires the command to actually spit a number to standard output, hence the use of the "wc -l" command. You could, if your version of grep supports it, instead use "grep -c", which instead of returning matchine lines instead prints out the number of matching lines.

Hence, the following three commands should get you equivalent results in csh:

if (`ps -ef | grep XWin | grep -v grep | wc -l` == 0 ) then
XWin
endif

and

if (`ps -ef | grep XWin | grep -cv grep` == 0 ) then
XWin
endif

and (note here we're explitcilty printing out the return value of the grep command):

if (`ps -ef | grep XWin | grep -qv grep; echo $?` > 0 ) then
XWin
endif