0

Click to see image I am trying to use the sed command to extract a string in parentheses from many strings that a terminal returns. For example, I want to extract the string "Glass" that is in parentheses:

In Terminal I execute a program that prints out:

People: Leela, Amy, Bender, Zack
Item: Ship, Food, Gum, Water
Delivery: Pizza, Newspaper, Plant
Broken: Gas Tank, Watch, (Glasses)  

For testing, purposes I wrote this in the terminal:

echo "Broken: Gas tank, Watch, (Glasses)" | sed 's/.*(\(.*\)).*/\1/'  

The terminal returned:

Glass

which is the correct answer. But When I try to declare it in the .c file, my IDE seems it cannot interpreter the sed command. It seems like I need to format the sed command. The way I am using the sed command is:

static const * getBrokenItem(void){
#define CMD " grep \"Broken: \" |sed 's/.*(\(.*\)).*/\1/'"
     FILE *fp = NULL;
     fp = open(CMD, "r");
     bla..bla...
     bla..bla...
}

The IDE (Visual Studio) does not like the "(" and ")" in

sed 's/.*(\(.*\)).*/\1/'"

I attached a snip here so it is easier to identify which "\(" and "\)" I'm referring to.

I have tried to add an additional "" next to the original "" since in C programming you need to do print("Backslash \") to print one backslash, but it did not work.

Can someone let me know what might be wrong please?

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
DavidKanes
  • 183
  • 1
  • 1
  • 10
  • 1
    don't use `system`. Why don't just use C string search functions? Just look for the `(` then the next `)` and extract the thing between them. If the regex is more complex then use a regex library – phuclv Mar 31 '20 at 03:20
  • Putting `#define` right in the middle of a function, especially when it's to define a constant string, is really inappropriate. Just pass the string in as an argument. As phuclv points out, though, since you're using C you have all the tools you need to parse this in C. Using `sed` is out of place. – tadman Mar 31 '20 at 03:26
  • 1
    If you want to have a literal backslash in the string you need to use `\\\` so ``#define CMD " grep \"Broken: \" |sed 's/.*(\\(.*\\)).*/\\1/'"`` – Jerry Jeremiah Mar 31 '20 at 03:26
  • So this is actually for an embedded device. I need to access to the device log and grab some information. So when you ssh on to the device, you enter a command, and then the terminal return with many lines of information. From that, I need to grab required information to store in a file. So I am using terminal commands – DavidKanes Mar 31 '20 at 03:28
  • parsing the log yourself is far less expensive than a `system` call – phuclv Mar 31 '20 at 04:51
  • As a side note, you should not get "Glass" as the result in your terminal. The word between the parenthesis is "Glasses" (plural). – Alexis Wilke Sep 16 '21 at 05:10

1 Answers1

0

Assuming, for sake of argument, that it is a good idea to run an external command at all, then you need to use the POSIX popen() function to run the command (and pclose() when finished):

FILE *fp = popen(CMD, "r");
…error check fp…
…read fp…
pclose(fp);

The Unix open() function returns a file descriptor (aka int) and not a file stream (aka FILE *). Using fopen() would return a file stream, but would fail to find a file with the exotic name represented by the command line. Using popen() runs the string as a command, and with "r" as the mode, leaves you with a file stream that you can read normally, and then close with pclose().

You could instead build the regular expressions into your program, possibly using the POSIX <regex.h> header and functions regcomp() and regexec(), etc. Or you could use a more powerful library; PCRE springs to mind.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Although I'd agree that using `popen()` under MS-Windows would be total craziness, it's done all the time on Unix. Actually many C programs do a lot of that all the time. – Alexis Wilke Sep 16 '21 at 05:12
  • Apparently, the function is called `_popen()` (has a leading leading underline) in the Microsoft C runtime. It may only work properly in Console programs or perhaps that has changed, see [this thread](https://stackoverflow.com/q/450865/3150802). The traditional way using the Win32 API is [more complicated](https://learn.microsoft.com/en-us/windows/win32/ProcThread/creating-a-child-process-with-redirected-input-and-output). – Peter - Reinstate Monica Sep 16 '21 at 05:34