Bash if run a command

I am having trouble with bash. I am trying to put a command in an if statement and then compare it to a string.

This works perfectly.

echo $(ipcs | grep Shared | awk '{print $2}')

When I put it in an if statement I get some problems.

$ if [ "$(ipcs | grep Shared | awk '{print $2}')" -eq "Shared"]; then                echo expression evaluated as true;             else                echo expression evaluated as false;             fi
bash: [: missing `]'
expression evaluated as false

$ if [ "$(ipcs | grep Shared | awk '{print $2}')" = "Shared"]; then                echo expression evaluated as true;             else                echo expression evaluated as false;             fi
bash: [: missing `]'
expression evaluated as false

$ if [ "$(ipcs | grep Shared | awk '{print $2}')" == "Shared"]; then                echo expression evaluated as true;             else                echo expression evaluated as false;             fi
bash: [: missing `]'
expression evaluated as false

I tried ==, =, and -eq because I wasn't sure which one to use.

Hi,

Need to enclose in single quotes like so;

if [ `$(ipcs | grep Shared | awk '{print $2}')` == "Shared"]

Regards

Dave

You need a space after the [ and before the closing ]

if [ "$(ipcs | grep Shared | awk '{print $2}')" = "Shared" ]; then 

Shorter is

if [ "$(ipcs | awk '/Shared/ {print $2}')" = "Shared" ]; then 

Both are not portable.

Those look more backticks to me `. On my system single quotes aren't slanted '. Are backticks better than double quotes?

That worked :). Can you please explain why you need spaces at the beginning and end [ ] brackets for if statements? I always forget when I don't do shellscripting for awhile.

I sometimes forget how awesome awk is :).

What do you mean by not portable? Is it not posix compatible? Is there a way to make it portable?

I don't understand what you're trying to do. On a system with no active message queues, shared memory segments, or semaphores, the output from ipcs will be something like:

iIPC status from <running system> as of Thu Oct  9 11:22:09 PDT 2014
T     ID     KEY        MODE       OWNER    GROUP
Message Queues:

T     ID     KEY        MODE       OWNER    GROUP
Shared Memory:

T     ID     KEY        MODE       OWNER    GROUP
Semaphores:

So, the output from:

ipcs|grep Shared|awk '{print $2}'

will be:

Memory:

and the condition in your if statement will always evaluate to false.

If, in addition to showing us code that doesn't work, you would also tell us what you're trying to do, we might be better able to help.

And, no. You do not want to enclose a command substitution in backquotes unless you are trying to perform a command substitution on the results of a command substitution.

It looks like we are using two different distros of Linux. Our output is a bit different. I am using Fedora.

$ ipcs

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 262145     bob        600        393216     2          dest         
0x00000000 2523138    bob        600        393216     2          dest         
0x00000000 2555907    bob        600        393216     2          dest         
0x00000000 3375108    bob        600        998400     2          dest         
0x00000000 3440645    bob        666        40         1                       

------ Semaphore Arrays --------
key        semid      owner      perms      nsems     
0x000005b1 262146     bob        600        6         

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    

I am working on a C project that spawns threads, creates shared memory, and creates semaphore arrays. It is annoying to have to keep typing or searching my bash history for:

ipcrm -s $(ipcs | grep bob | awk '{printf "%s ",$2}')
ipcrm  shm $(ipcs | grep bob | awk '{printf "%s ",$2}')

So I was thinking I could do something like this.

if [ `$(ipcs | grep Shared | awk '{print $2}')` == "Shared"]
ipcrm  shm $(ipcs | grep bob | awk '{printf "%s ",$2}')

I wanna do that first behavior until $2 equals Semaphore.

if [ `$(ipcs | grep Semaphore | awk '{print $2}')` == "Semaphore"]
ipcrm -s $(ipcs | grep bob | awk '{printf "%s ",$2}'

)

I am not sure how to this. I have been reading the bash documentation for several days with no luck.

You had several options given to you in your duplicate thread, and it's not clear whether you tried any of them. Particularly, my suggestion with the while loop and printing the options to help figure out why it's not matching when it apparently should.

Please try that, and get back to me, otherwise I'm just wild guessing.

We are not using different Linux distros. I am using a UNIX system where the output produced by the ipcs utility follows the formatting requirements specified by the standards.

If what you are trying to do is to remove message queues, shared memory segments, and semaphore sets that you own, the problem you stated in this thread seems to be useless. If you save the following script in $HOME/bin/cleanipc :

#!/bin/bash
# Usage: ipcs [-mqs] | cleanipc
#
# This script reads output from the ipcs utility from standard input and uses
# ipcrm to remove all message queues, shared memory segments, and semaphore
# sets whose owner is "bob".
echo ipcrm $(awk -v user="bob" '
$2 == "Shared" {
	type = " -m "
	next
}
$2 == "Message" {
	type = " -q "
	next
}
$2 == "Semaphore" {
	type = " -s "
	next
}
/^0x/ && $3 == user {
	o = o type $2
}
END {	print o
}')

and make it executable using:

chmod +x $HOME/bin/cleanipc

then the command:

ipcs -ms | cleanipc

it will show you an ipcrm command that will remove all shared memory segments and semaphore sets owned by "bob". If that looks like what you want to do, remove the echo shown in red in the script to have the script actually remove those IPC facilities.

Use different (or no options) on the ipcs command to process just message queues ( -q ), just shared memory segments ( -m ), just semaphore sets ( -s ), or everything (no options).

Note that the above script will NOT work on any system where the output produced by ipcs conforms to the standards. If your ipcs produced standard format output, the following code in the above awk script:

$2 == "Shared" {
        type = " -m "
        next
}
$2 == "Message" {
        type = " -q "
        next
}
$2 == "Semaphore" {
        type = " -s "
        next
}
/^0x/ && $3 == user {
        o = o type $2
}

would be replaced by:

$1 ~ /^(m|q|s)$/ && $5 == user {
        o = o " -"$1 $2
}
1 Like

Does my ipcs conform to standards? How do I know if it conforms to standards? The first method worked.

Is my understanding of this correct? After Shared is matched. Then it runs what is in {}. Then the next makes it read the next line? It ignore the Message block and Semaphore block until the column 2 is matched? It then goes to ^0x block? The process starts back over on the next line?

$2 == "Shared" {
    type = " -m "
    next
}

Can you please explain this part? I know you are anchoring the 0 to the beginning, then you making sure column 3 matches user which has been set to bob.

/^0x/ && $3 == user {
    o = o type $2

Did I do this right? I replaced everything in the single quotes ' '. It looked like you needed to keep the first part. I thought my ipcs conformed to standards but the first method worked.

#!/bin/bash
# Usage: ipcs [-mqs] | cleanipc
#
# This script reads output from the ipcs utility from standard input and uses
# ipcrm to remove all message queues, shared memory segments, and semaphore
# sets whose owner is "bob".
echo ipcrm $(awk -v user="bob" '
$1 ~ /^(m|q|s)$/ && $5 == user {
        o = o " -"$1 $2
}')

Thank you for your very detailed explanation. I wouldn't have remembered to use the bin directory.

PS: If you use mmap()'d files not shared memory for these functions, you can kiss ipcrm and all that root stuff goodbye. Also no sudo needed, everyone can do shared memory in their own files, and the files are simple to dump after an abort or to monitor during a long run.

No. Yes. Sure. And, no!

The output you showed us from the ipcs utility on your Fedora Linux distro does not conform to the standard in lots of ways. You need to keep the full script I gave you (with the exception of the echo ) to get something that will work with the ipcs utility you have.

You said that the output from your ipcs looks like:

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 262145     bob        600        393216     2          dest         
0x00000000 2523138    bob        600        393216     2          dest         
0x00000000 2555907    bob        600        393216     2          dest         
0x00000000 3375108    bob        600        998400     2          dest         
0x00000000 3440645    bob        666        40         1                       

------ Semaphore Arrays --------
key        semid      owner      perms      nsems     
0x000005b1 262146     bob        600        6         

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages

so:

/^0x/ && $3 == user {
        o = o type $2
}

selects lines where the 1st two characters on the line are 0x and the 3rd field is bob (which I marked in red above). For each selected line it adds a string based on the section of the output from ipcs and the ID from that line to the string saved in the variable o .

If you had a conforming ipcs utility, the output for the last line in each section would have been:

m 3440645  0x00000000 666        bob        40         1                       
s 262146   0x000005b1 600        bob        6         

instead of the output you showed us:

0x00000000 3440645    bob        666        40         1                           
0x000005b1 262146     bob        600        6         

So, for other people reading this thread who do have a conforming ipcs , they could use:

#!/bin/bash
# Usage: ipcs [-mqs] | cleanipc
#
# This script reads output from the ipcs utility from standard input and uses
# ipcrm to remove all message queues, shared memory segments, and semaphore
# sets whose owner matches is the person who invoked this utility as determined
# by $USER from the environment.
ipcrm $(awk -v user="$USER" '
$1 ~ /^(m|q|s)$/ && $5 == user {
	o = o " -"$1 $2
}
END {	print o
}')
1 Like