how to detect when compiler emits an error - c++

To compile a C++ project, I want to write a perl script to compile my program and see if the compilation went wrong or not. If the compiler gives any compilation error, I'll need to perform some other task.
The perl script will be something like this:
#l1 = `find . -name '*.c'`;
#l2 = `find . -name '*.cpp'`;
#l3 = `find . -name '*.cc'`;
my $err;
my $FLAGS = "-DNDEBUG"
push(#l , #l1, #l2, #l3);
chomp(#l);
foreach (#l) {
print "processing file $_ ...";
$err = `g++ $_ $FLAGS`;
if($err == something) {
#do the needful
}
}
so what should be something?

You should check $? instead, after g++....
perlvar
$?
The status returned by the last pipe close, backtick (`` ) command,
successful call to wait() or waitpid(), or from the system() operator.
The exit value of the subprocess is really ($?>> 8)
So you should check if g++ returned 0 (success) or non-zero.
if ($? >> 8) {
/* Error? */
}

IPC::System::Simple/IPC::Run3 make this easier

Related

Creating an alert function in Bash

I wanted to create a function in bash similar to a default alias I got in Ubuntu, looking like:
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
This creates a simple notification after a command has been issued with it.
For example, using
history | grep vim; sleep 5; alert
gives a notification after the sleep is done, simply saying
history | grep vim; sleep 5;
I would like to write the alert into a bash function instead, which have given some trouble with the regex.
I have tried:
function alert2 () {
ICON=$([ $? = 0 ] && echo terminal || echo error)
MSG=$(history | tail -n1 | sed -e s/^\s*[0-9]\+\s*//\;s/[\;\&\|]\s*alert$//)
notify-send --urgency=low -i $ICON $MSG
}
which would output both the linenumber in history when called itself, and give an Invalid number of options when called such as the first example.
Is this possible, and if so, how? Is it simply my regex that is faulty?
I'm running on WSL, so don't have notify-send installed:
function alert2 () {
ICON=$([ $? = 0 ] && echo terminal || echo error);
MSG=$(history | tail -n1| sed -e 's/^\s*[0-9]\+\s*//;s/[;&|]\s*alert2$//');
echo $ICON $MSG;
}
jadams#Temp046317:~/code/data-extract$ cat /etc/apt/sources.list > /dev/null ; alert2
terminal cat /etc/apt/sources.list > /dev/null
I'm hoping that this would work for you (instead of the echo):
notify-send --urgency=low -i "$ICON $MSG"

How can I get the return value of `wget` from a sh script into an `int` variable

OS: Linux raspberrypi 4.19.58-v7l+ #1245 SMP Fri Jul 12 17:31:45 BST 2019 armv7l GNU/Linux
Board: Raspberry Pi 4
I have a script:
#!/bin/bash
line=$(head -n 1 /var/www/html/configuration.txt)
file=/var/www/html/4panel/url_response.txt
if [ -f "$file" ]; then
wget_output=$(wget -q -i "$line" -O $file --timeout=2)
echo "$?"
else
echo > $file
chown pi:pi $file
fi
which I call from a C++ program using:
int val_system = 0;
val_system = system("/var/www/html/4panel/get_page.sh");
std::cout<<"System return value: "<<val_system<<std::endl;
If there is something wrong with the script, echo "$?" will output the return value of wget, but val_system will always be 0.
Does system() returns the value of echo "$?" ? In which case 0 is correct. And if that is the case how can I put the return value of wget in val_system ?
I have taken a situation in which echo "$?" always returns 8, basically I've entered an incorrect URL and:
I have tried deleting echo "$?" but val_system still returned 0;
With echo "$?" deleted I have changed the wget line to wget -q -i "$line" -O $file --timeout=2 and val_system now returns 2048.
None of my attempts bared any fruit and I have come here to seek guidance. How can I make val_system / system() return what echo "$?" returns ?
How can I get the return value of wget from the script into an int variable that's inside the C++ program that calls the script ?
The integer value system() returned contains extra information about executed command's status along with its exit code, see system() and Status Information. You need to extract exit code using WEXITSTATUS macro, like:
std::cout << "System return value: " << WEXITSTATUS(val_system) << std::endl;
If you want to echo the status and return it, you will need to save the value of $? to a variable, and exit with it explicitly.
wget_output=$(wget -q -i "$line" -O $file --timeout=2)
status=$?
...
echo $status
...
exit $status
If you don't need to execute echo or any other command between the call to wget and the end of the script, you can rely on the script exiting with the last status (i.e the one corresponding to the call to `wget) implicitly.

Piping output of shell command to grep causes "grep: write error"

I wrote a tool in Crystal that takes some command line parameters, and turns those into, basically, "find stuff | xargs grep" where xargs is instructed to use multiple processes. This is run via Process.run, and output and error are redirected into a custom IO object which filters what comes out of grep a bit, writing everything that isn't filtered into STDOUT.
When I run this normally, it mostly seems to run fine. There do seem to be some instances of output getting cut off before the search completes though, so I'm not sure I can fully trust the results. When I pipe the output from this command into grep, however, it always cuts off the search early and says "grep: write error". I have no idea why this is happening, and would love some help. Eventually I'll likely rewrite this to do everything in pure Crystal, but for now this is a quick solution to search the codebase I'm working on.
Here is the code that is getting run:
class FindFilterIO
include IO
##generic_filter = [".diff", ".iml", "/target/"]
##web_filter = [".css", ".js", ".jsp", ".ftl"]
def initialize(#web_search : Bool = false)
end
def read(slice : Bytes)
raise "FindFilterIO does not support reading!"
end
def write(slice : Bytes)
str = String.new slice
if ##generic_filter.any? { |e| str.includes? e }
return
end
if #web_search
if !##web_filter.any? { |e| str.includes? e }
return
end
end
STDOUT.write(slice)
end
end
cmd = "find . -not \\( -path ./.svn -prune \\) " \
"-not \\( -path ./.idea -prune \\) " \
"-type f -print0 " \
"| xargs -0 -P 1 -n 100 grep -E -n --color=always "
cmd += if #html_id
"'id=['\"'\"'\"]#{#search_text}['\"'\"'\"]|\##{#search_text}'"
elsif #html_class
"'class=['\"'\"'\"]#{#search_text}['\"'\"'\"]|\\.#{#search_text}'"
else
"'#{#search_text}'"
end
io = FindFilterIO.new web_search: (#html_id || #html_class)
Process.run(cmd, output: io, error: io, shell: true, chdir: File.join(#env.home_dir, #env.branch, "repodir"))
This seems to have been fixed now that the issue at https://github.com/crystal-lang/crystal/issues/2065 has been closed. Will need to do some more testing to make sure it's totally fixed, but using my older code seems to be working fine now.

Bash variable substitution in a function

I have a function read_command defined as:
function read_command {
local __newline __lines __input __newstr __tmp i;
exec 3< "$*";
__newline=$'\n';
__lines=();
while IFS= read <&3 -r __line && [ "$__line" != '####' ]; do
echo "$__line";
__lines+=("$__line");
done
while IFS= read <&3 -r __line && [ "$__line" != '####' ]; do
read -e -p "${__line#*:}$PS2" __input;
local ${__line%%:*}="$__input";
done
__command="";
for i in "${__lines[#]}"; do
__tmp=$(echo "${i}");
__command="${__command} ${__newline} ${__tmp}";
done
echo -e "$__command";
}
In the current directory there is a file named "test", with the following
content:
greet ${a:-"Bob"}
greet ${b:-"Jim"}
####
a: name of friend a
b: name of friend b
####
In the terminal, the command executed is
read_command test
With no input, I am expecting the output of the last statement to be:
greet Bob
greet Jim
But what I get is:
greet ${a:-"Bob"}
greet ${b:-"Jim"}
What is wrong here?
Edit: As suggested by David, adding eval works in some cases except the following one.
j=1;i="export DISPLAY=:0 && Xephyr :${j}&";k=$(eval echo "$i");
echo $k
export DISPLAY=:0
I am expecting k to be "export DISPLAY=:0 && Xephyr :1&", what's wrong here?
Edit: I tried with the following
k=$(eval "echo \"$i\"")
This is the link to the script I am working on.
https://gist.github.com/QiangF/565102ba3b6123942b9bf6b897c05f87
During the first while loop, in echo "$__line", you have __line='greet ${a:-"Bob"}'. When you try to print that, Bash won't be expanding ${a:-"Bob"} into Bob. (Even if you remove the quotes around $__line this won't happen.) To get that effect, you need to add eval, as in, e.g., eval echo "$__line". Unfortunately eval comes with its can of worms, you have to start worrying about interactions between quoting levels and such.

Perl: suppress output of backtick when file not found

In my code :
$status = `ls -l error*`;
It shows output : ls *error No such file or directory.
How can I suppress this message. I am interested in determining that the error files are generated or not. If yes, I need the list of files else ignore (without printing the message)
By running it like
$status = `ls -l error* 2> /dev/null`;
and suppressing the external command's output to standard error.
If you just need the file names (and not all the other info that ls's -l switch gives you), this can be accomplished in pure Perl with a statement like
#files = glob("error*");
if (#files == 0) {
... there were no files ...
} else {
... do something with files ...
}
and if you do need all the other info you get from ls -l ..., applying the builtin stat function to each file name can give you the same information.