Using grep with execl() - c++

A little context for my project: We have an arbitrary number of files that need a separate process for each file then need to search using an exec() call to find every time a specific KEY is used. I know how to use grep from the command line using this command:
grep -o KEY FILENAME.txt | wc -l > OUTPUT.txt
But I cannot figure out how to do this in c++. I found a thread on here that gave me this line.
execl("/bin/grep","grep",pattern,filename,NULL);
It compiles and runs so I think it works but the problem is I need to output the number of times the pattern occurred to a file and I tried the line below but expectedly it didn't work. It gave this error "grep: out.txt: No such file or directory"
execl("/bin/grep", "grep",pattern,fileName,output,NULL);
Here are the directions of this part of my project.
You can do this by means of the
system call exec() , providing it with the path to the executable of the shell (typically, /bin/sh )
and, as arguments of /bin/sh , the string -c and the string corresponding to the search command
( grep -o ... ).
Some guidance here would be much appreciated!

For the actual execution as you would do on command line would be:
execl("/bin/sh", "/bin/sh", "-c", "grep -o KEY FILENAME.txt | wc -l > OUTPUT.txt")
This will mean that the shell would take the line grep -o KEY FILENAME.txt | wc -l > OUTPUT.txt, interpret it and run it. Note that this will include wild card expansion and all what the shell does.
Then of course if you wan't to continue after it has completed you will have to fork first because execl does not return if it's successful at starting the program (ie bash).

Related

Library compiled to architecture x64 with error in Arm architecture

I'm developing a C++ library that has a piece of shell script code that return the name of a specific serial port. When I run this script in console either X64 desktop or Arm enviorment the script returns the right answer. My problem ocur when I execute the same script inside of the library, the returns shows bad formed string like ÈÛT¶ÈÛT¶¨a , but the expected is /dev/ttyACM0.
The script that run inside of library:
Script
bash -c 'for sysdevpath in $(find /sys/bus/usb/devices/usb*/ -name dev);do(syspath="${sysdevpath%/dev}";devname="$(udevadm info -q name -p $syspath)";[[ "$devname" == "bus/"* ]]&& continue;teste="$(udevadm info -q property --export -p $syspath | grep -i "company_name")";if [[ ! -z "${teste// }" && $devname == *"ttyACM"* ]]; then echo "/dev/$devname";fi);done;' 2> /dev/null
The following piece of code is used to save the content returned by the script into a file.
code c++
pfFile = fopen(CONFIG_FILE, "w+");
fwrite(result,strlen(result), 1, pfFile);
fclose(pfFile);
return 0;
Besides you didn't include what is result and where it comes from in your C++ code; you selected the hardest way to do this. Code running shell scripts inside a library most likely cause nothing but headaches.
Basically you can create an udev rule for your device to create an unique and stable file in /dev to access it. You can create one like this one in the ArchWiki
KERNEL=="video[0-9]*", SUBSYSTEM=="video4linux", SUBSYSTEMS=="usb", ATTRS{idVendor}=="05a9", ATTRS{idProduct}=="4519", SYMLINK+="video-cam1"

Using grep to match one digit with TCL

The file that I want to grep contains many lines.
I want to grep lines which contain only 1 digit: "0" or "1".
I used this command:
exec grep -e "^\[0-1\]{1}$" file
But I got:
child process exited abnormally
What's wrong with RegExp of grep?
The most common issue when running grep as a Tcl subprocess is that it exits with a non-zero error code when it doesn't find anything at all. This always causes Tcl to throw an exception. The simplest workaround is perhaps this:
exec /bin/sh -c {grep -e '^[0-1]{1}$'; true} < file
Note that we are feeding in the file using a redirection here; this means that it is not necessary to strip the name of the file from the results.

Kill command line process and restart if STDOUT changes to what I'm looking for?

I have a question - I'm running a process from the command line that has some problem and poops out every few hours or so. While I'm looking into the issue, I'd like to spawn the process from something that monitors STOUT for certain string/regex and kills and restarts the process if it outputs something that indicates that it's broken.
I know I could do this the vanilla way by rolling my own Python/Ruby script but I was wondering if there's any nifty tools I can use to make this a bit cleaner? This is on Windows but I have cygwin in case the answer involves a unix command line process.
program | grep CRASH_STRING | xargs -l 1 sh -c 'killall program && program'
Well, that will do it once. I'm not sure how to make that work in a loop. I thought about it some more, and it can probably be done by redirecting stdout to a named pipe. But the shell script will probably end up more unwieldy than writing a watchdog in a scripting language.
But the idea with a pipe is something like this:
mkfifo /tmp/fifo
program > /tmp/fifo&
while :
do
grep "CRASH_STRING" /tmp/fifo | xargs -l 1 sh -c 'killall program && program > /tmp/fifo&'
done

Use GDB to debug a C++ program called from a shell script

I have a extremely complicated shell script, within which it calls a C++ program I want to debug via GDB. It is extremely hard to separate this c++ program from the shell since it has a lot of branches and a lot of environmental variables setting.
Is there a way to invoke GDB on this shell script? Looks like gdb requires me to call on a C++ program directly.
In addition to options mentioned by #diverscuba23, you could do the following:
gdb --args bash <script>
(assuming it's a bash script. Else adapt accordingly)
There are two options that you can do:
Invoke GDB directly within the shell script. This would imply that you don't have standard in and standard out redirected.
Run the shell script and then attach the debugger to the already running C++ process like so: gdb progname 1234 where 1234 is the process ID of the running C++ process.
If you need to do things before the program starts running then option 1 would be the better choice, otherwise option 2 is the cleaner way.
Modify the c++ application to print its pid and sleep 30 seconds (perhaps based on environment or an argument). Attach to the running instance with gdb.
I would probably modify the script to always call gdb (and revert this later) or add an option to call gdb. This will almost always be the easiest solution.
The next easiest would be to temporarily move your executable and replace it with a shell script that runs gdb on the moved program. For example, in the directory containing your program:
$ mv program _program
$ (echo "#!/bin/sh"; echo "exec gdb $PWD/_program") > program
$ chmod +x program
Could you just temporarily add gdb to your script?
Although the answers given are valid, sometimes you don't have permissions to change the script to execute gdb or to modify the program to add additional output to attach through pid.
Luckily, there is yet another way through the power of bash
Use ps, grep and awk to pick-out the pid for you after its been executed. You can do this by either wrapping the other script with your own or by just executing a command yourself.
That command might look something like this:
process.sh
#!/usr/bin/env bash
#setup for this example
#this will execute vim (with cmdline options) as a child to bash
#we will attempt to attach to this process
vim ~/.vimrc
To get gdb to attach, we'd just need to execute the following:
gdb --pid $(ps -ef | grep -ve grep | grep vim | awk '{print $2}')
I use ps -ef here to list the processes and their arguments. Sometimes, you'll have multiple instances of a program running and need to further grep down to the one you want
the grep -ve grep is there because the f option to ps will include the next grep in its list. If you don't need the command arguments for additional filtering, don't include the -f option for ps and ignore this piece
grep vim is where we're finding our desired process. If you needed more filtering, you could just do something like grep -E "vim.*vimrc" and filter down to exactly the process that you're trying to attach to
awk '{print $2}' simply outputs just the process' pid to stdout. Use $1 if you're using ps -e instead of ps -ef
My normal setup is to run such script that starts my process in 1 tmux pane and having typed something similar to the above in a bottom pane. That way if I need to adjust the filtering (for whatever reason), I can do it pretty quickly.
Usually though, it will be the same for a specific instance and I want to just attach automatically after its been started. I'll do the following instead:
runGdb.py
#!/usr/bin/env bash
./process.sh &
PID=$(ps -ef | grep -ve grep | grep -E "vim.*vimrc" | awk '{print $2}')
#or
#PID=$(ps -e | grep vim | awk '{print $1}')
gdb --pid $PID
This assumes that the original process can be safely run in the background.

C++ program parsing arguments

I want to make a program to be called from the command line like this:
myprogram.exe -F/-T FILE/TEXT -W FILE.WAV -P FILE.PHO -A
They are 3 parts:
myprogram.exe
-F OR -T and the File or text
-W FILE -P FILE and -A (At least one, up to 3, in any order (or not, if it's complicated))
So it can be:
myprogram.exe -T "Text Text, test text" -A
or:
myprogram.exe -F FILENAME -A
or:
myprogram.exe -F FILENAME -P FILENAME -W FILENAME
etc.
-A is one function (needs the text or the file)
-W writes a WAV file with the info from the text/file
-P does something similar to -W
What is the best way to handle it? Analyzing argv[x] one by one, and deciding with ifs? Something easier?
I am new to programming and using VS2008.
You can parse them manually or use Boost.Program_options.
Analyizing argv[x] one by one
That's what I would do. Maybe maintain a counter of the current element ...
unsigned int cur = 0;
if (argc <= 1) {
.. error
}
if (!strncmp(argv[cur],"-T",2)) {
.. process
++cur;
}
...
for (;cur < argc;++cur) {
if (!strncmp(argv[cur],"-F",2)) {
.. process
}
else if ...
}
There are some command line parers out there. Unix has getopt, for example.
I'd use getopt if you can: it's simple enough. It'll handle combined options too (like in ls -lt instead of ls -l -t) and it handles options with arguments as well, and the order in which they appear also doesn't matter. All this makes it "standard" to people used to command line arguments (normally order of options is irrelevant, except when giving contradictory options...).
this is already done by others, so I wouldn't spend all your time on it if I were you.
Look at Boost's ProgramOptions for example.