How to exit calling script in csh? - exit

I have a csh script (a.csh) which calls another (./b.csh). How do I exit from a.csh if some condition is not satisfied while running b.csh?
Here is how I call b.csh
b.csh >&! b.csh.log
There is a related question for bash How to exit all the calling scripts in bash?.

Inside b.csh, use this to terminate a.csh without terminating b.csh:
set PPID = `ps -ef | awk -v pid="$$" '{if ($2 == pid) {print $3}}'`
kill $PPID
In bash-like shells, $PPID is defined, but for csh we have to extract it manually.
$$ returns the current process ID (pid) (that is, the pid of b.csh).

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"

I use perl in a bash script that pipes to a regular expression. How do I also set a variable in the piped stream?

I have created a bash script that runs on several machines that contain different git local repositories. It tests many conditions and tells me if the repository has uncommitted files, untracked files, and one test in particular tells me that the local is ahead or behind the remote by the number of commits. The problem with the script is that it doesn't return or set an 'ok' flag which I use to echo the "ok" message if everything is in sync. So, I get the message that it's ahead or behind, but then get the "ok" message. Here is the portion of the script that does the ahead or behind, and I can't see how to get it to set an ok = false somehow.
git fetch>/dev/null && git branch -v |
perl -wlne'
print "$ENV{reponame} [$1] --> $3 $2"
if /^..(\S+)\s+([a-f0-9]+)\s+(\[(?:ahead|behind)\s+\d+\])/
' |
while IFS= read -r MOD; do
ok=false
printf ' %s\n' "$MOD" # Replace with code that uses $MOD
done
if $ok; then
echo " OK --> $reponame [$br] $rev"
fi
I copied this from another script and don't really understand the IFS = read -r MOD; section that I thought might set the flag, but it doesn't occur.
This is the output I get:
bin [develop] --> [behind 1] 026e1ad
OK --> bin [develop] 026e1ad
OK --> notes [develop] 4cd077f
OK --> indecks [develop] e6b4293
OK --> queue [develop] 5469679
OK --> frameworks [master] 05fedb6
OK --> dashboard [isolate] f8b1101
OK --> nodejs [develop] 5af2ea7
OK --> perl-forth [master] 45cc837
OK --> blog [master] c19edfd
Note that for bin I get:
bin [develop] --> [behind 1] 026e1ad
OK --> bin [develop] 026e1ad
I'd rather not get that OK after the behind 1! Another script checks for any non-OK in the left column and sends me an email.
With the perl and all the piping, how could I set the ok variable before it prints?
In most shell implementations, all processes in a pipeline are run in a subshell. In this case, you're running a while loop at the end of a pipeline, so it (and it alone) is in the subshell. Whether you set ok to false or not, it has no effect on the if block because that's run the main shell, which doesn't inherit variables from the subshell.
zsh and AT&T ksh (but not other ksh implementations) execute the last command in the main shell and not a subshell. POSIX permits either behavior, but the bash behavior is far more common among shells.
The easiest way to handle this is to run the entire command you're interested in in a subshell:
git fetch>/dev/null && git branch -v |
perl -wlne'
print "$ENV{reponame} [$1] --> $3 $2"
if /^..(\S+)\s+([a-f0-9]+)\s+(\[(?:ahead|behind)\s+\d+\])/
' |
(while IFS= read -r MOD; do
ok=false
printf ' %s\n' "$MOD" # Replace with code that uses $MOD
done
if $ok; then
echo " OK --> $reponame [$br] $rev"
fi)
This puts both parts using the ok variable in the same subshell, so you can modify it and it will have an effect.

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.

Read each line to match a pattern

I have the following details in a input.txt file. My requirement is to match the patterns "Stopped|Aborted|isn't running" in any of the lines, need to print that line. And if the all are in "Running" state need to print a single message that "ALL ARE RUNNING".
SVRSVC1 SVRSVC1 NAME SVRSVC1 PID Running
SVRSVC2 SVRSVC2 NAME SVRSVC2 PID Running
SVRSVC3 SVRSVC3 NAME SVRSVC3 PID Running
SVRSVC4 SVRSVC4 NAME SVRSVC4 PID Running
SVRSVC5 SVRSVC5 NAME SVRSVC5 PID isn't running
SVRSVC6 SVRSVC6 NAME SVRSVC6 PID Running
SVRSVC7 SVRSVC7 NAME SVRSVC7 PID Running
SVRSVC8 SVRSVC8 NAME SVRSVC8 PID Aborted
SVRSVC9 SVRSVC9 NAME SVRSVC9 PID Running
SVRSVC10 SVRSVC10 NAME SVRSVC10 PID Running
SVRSVC11 SVRSVC11 NAME SVRSVC11 PID Running
SVRSVC12 SVRSVC12 NAME SVRSVC12 PID Stopped
SVRSVC13 SVRSVC13 NAME SVRSVC13 PID Running
SVRSVC14 SVRSVC14 NAME SVRSVC14 PID running
Here is code i have written but i would like to know if this is the right approach or any easiest way for this. ?
#set -x
RUNTIME=`date +%Y%m%d_%H%M%S`
TOTAL_RUNSTAT=$(more input.txt | wc -l)
while read -r line; do
if [[ $line =~ Stopped|Aborted|"isn't running" ]]; then
echo $line;
elif [[ $line =~ Running ]]; then
echo $line >> runstatuslog_$RUNTIME;
if [[ `more runstatuslog_$RUNTIME | wc -l` =~ $TOTAL_RUNSTAT ]]; then
echo "ALL SERVICES RUNNING";
fi
fi
done < input.txt
Here is the expected output:
If found "Stopped|Aborted|isn't running" print the line.
SVRSVC5 SVRSVC5 NAME SVRSVC5 PID isn't running
SVRSVC8 SVRSVC8 NAME SVRSVC8 PID Aborted
SVRSVC12 SVRSVC12 NAME SVRSVC12 PID Stopped
if not found, check to see if all are running then, print message "ALL ARE RUNNING"
ALL ARE RUNNING.
It's not clear why you'd want to test for all of the nun-Running states. This will produce the output you asked for from that input:
$ awk '{lc=tolower($0)} lc~/isn\047t running$/ || lc!~/running$/{c++;print} END{if (!c) print "ALL ARE RUNNING"}' file
SVRSVC5 SVRSVC5 NAME SVRSVC5 PID isn't running
SVRSVC8 SVRSVC8 NAME SVRSVC8 PID Aborted
SVRSVC12 SVRSVC12 NAME SVRSVC12 PID Stopped
If that's not what you want then edit your question to clarify your requirements and provide more truly representative sample input/output.
Using grep
grep -E "Stopped$|Aborted$|isn't running$"
-E for extended regex
$ is to mark the end of the line
| is for logical or
Using sed
sed -nE "/Stopped$|Aborted$|isn't running$/p" file
-n to supress the output
/pattern/ is to process only lines that match the pattern
p command is to print the line
Using awk
awk '{if($NF != "Running"){i++;print}}
END{if(i == 0){printf "All are running\n"}}' file
Here we check if the last field $NF is anything but "Running", if so execute the default action, ie print the record. This will not match the running in isn't running as the match is case sensitive.

Get PID of new process

So I'm creating a process in Perl like this:
my $process = `nohup ./run > /dev/null 2>&1 &`;
Which returns something along the lines of
[1] 2905
How do I go about getting the process ID from this so later on in the script execution I can run something like:
exec("kill -9 $pid");
Here's what I've got so far:
/\[1\] ([0-9]+)/g
but it looks quite messy, is there any way to improve upon this regular expression? Will that regex always work? Is there any case where it wont be [1]?
how about
#ar = split(/\s+/, $process);
$pid = $ar[1];
You should probably be using a "fork and exec" pattern here.
if (my $pid = fork()) {
# You're in the parent process
# $pid contains the PID of the new child process
...
} else {
# You're in the new child process
# exec() your new command
exec($cmd);
# Execution never gets here
}
Edit: Actually, given that you're basically creating a daemon process here, perhaps you should look at Proc::Daemon instead.