Script executes but fails to increment - bash

So I have this shell script that I think should run a given number of times, sleep then resume, and output the results to a log file
#!/bin/bash
log=/path/to/file/info.log
a=$(COMMAND1 | cut -d : -f 2)
b=$(COMMAND2 | grep VALUE| cut -c 7,8)
for i in {1..4}
do
echo "Test" $i >> $log
date >> $log
echo $a >> $log
echo "$((-113 + (($b * 2)))) VALUE" >> $log
sleep 60
done
When I run ps -ef | grep scriptname.sh it seems the script does run. Executes once then the PID is gone as if the run has completed.
I have tested the script and know that it is running and capturing the data I want. But I do not understand why its not incrementing and not sure why its ending earlier than expected.
info.log output sample
Test {1..4}
DATE IN UTC
EXPECTED VALUE OF a
EXPECTED VALUE OF b
Note that the output is literally "Test {1..4}" not "Test 1" "Test 2" Test 3" and so on, as I would expect.
I have run the script as ./scriptname.sh & and as /path/to/file/scriptname.sh &
I have read that there is a difference in running the script with sh and bash though I dont fully understand what effect that would have on the script. I am not a software person at all.
I have tried to run the script with nohup to keep it running in the background if I close the terminal. I also thought the & in the command was supposed to keep the script running in the background. Still it seems the script does not continue to run
I previously asked this question and it was closed, citing that it was similar to a post about the difference between sh and bash...but thats not my main question.
also echo "$BASH_VERSION" returns nothing, a blank line. echo "$-" returns smi, and I have no idea what that means. but bash --version returns:
BusyBox v1.17.1 (2019-11-26 10:41:00 PST) built-in shell (ash)
Enter 'help' for a list of built-in commands.
So my questions are:
If running the script with sh - is that done with ./scriptname.sh & and running the script with bash is /path/to/file/scriptname.sh &...and if so what effect does that have on how the script code is processed? that is - is using sh or bash. I do not fully understand the difference between the two
why does the script not continue to run when I close the terminal? This is my big concern. I would like to run this script hourly for a set period of time. Every time I try something and come back I get one instance in the log.

Neither brace expansion nor seq are part of the POSIX specification. Use a while loop.
log=/path/to/file/info.log
a=$(COMMAND1 | cut -d : -f 2)
b=$(COMMAND2 | grep VALUE| cut -c 7,8)
i=1
while [ "$i" -le 4 ]; do
printf 'Test %s\n' "$i"
date
printf '%s\n' "$a"
printf '%s\n' "$((-113 + (($b * 2)))) VALUE"
sleep 60
i=$((i+1))
done >> "$log"
(I suspect that you want to move the assignments to a and b inside the loop as well; right now, you are simply writing identical files to the log at each iteration.)

Related

Using while read, do Loop in bash script, to parse command line output

So I am trying to create a script that will wait for a certain string in the output from the command that's starting another script.
I am running into a problem where my script will not move past this line of code
$(source path/to/script/LOOPER >> /tmp/looplogger.txt)
I have tried almost every variation I can think of for this line
ie. (./LOOPER& >> /tmp/looplogger.txt)
bash /path/to/script/LOOPER 2>1& /tmp/looplogger.txt etc.
For Some Reason I cannot get it to run in a subshell and have the rest of the script go about its day.
I am trying to run a script from another script and access it's output then parse line by line until a certain string is found
Then once that string is found my script would kill said script (which I am aware if it is sourced then then the parent script would terminate as well).
The script that is starting looper then trying to kill it-
#!/bin/bash
# deleting contents of .txt
echo "" > /tmp/looplogger.txt
#Code cannot get past this command
$(source "/usr/bin/gcti/LOOPER" >> /tmp/ifstester.txt)
while [[ $(tail -1 /tmp/looplogger.txt) != "Kill me" ]]; do
sleep 1
echo ' in loop ' >> /tmp/looplogger.txt
done >> /tmp/looplogger.txt
echo 'Out of loop' >> looplogger.txt
#This kill command works as intended
kill -9 $(ps -ef | grep LOOPER | grep -v grep | awk '{print $2}')
echo "Looper was killed" > /tmp/looplogger.txt
I have tried using while IFS= read -r as well. for the above script. But I find it's syntax alittle confusing.
Looper Script -
./LOOPER
#!/bin/bash
# Script to test with scripts that kill & start processes
let i=0
# Infinite While Loop
while :
do
i=$((i+1))
until [ $i -gt 10 ]
do
echo "I am looping :)"
sleep 1
((i=i+1))
done
echo "Kill me"
sleep 1
done
Sorry for my very wordy question.

When using exec with &, the final command does not run

It seems the code after if/fi is not running. Here is what I have:
I have a script, /my/scripts/dir/directoryPercentFull.sh:
directoryPercentFull="$(df | grep '/aDir/anotherDir' | grep -o '...%' | sed 's/%//g' | sed 's/ //g')"
if [ $directoryPercentFull -gt 90 ]
then
echo $directoryPercentFull
exec /someDir/someOtherDir/test01.sh &
exec /someDir/someOtherOtherDir/test02.sh &
exec /someDir/yetAnotherDir/test03.sh
fi
echo "Processing Done"
The scripts being called are:
/someDir/someOtherDir/test01.sh
#!/usr/bin/env bash
echo "inside test01.sh"
sleep 5
echo "leaving test01.sh"
/someDir/someOtherOtherDir/test02.sh
#!/usr/bin/env bash
echo "inside test02.sh"
sleep 5
echo "leaving test02.sh"
/someDir/yetAnotherDir/test03.sh
#!/usr/bin/env bash
echo "inside test03.sh"
sleep 5
echo "leaving test03.sh"
running the script by cd-ing to /my/scripts/dir and then doing ./directoryPercentFull.sh gives:
OUTPUT:
93
inside test03.sh
inside test02.sh
inside test01.sh
leaving test03.sh
leaving test01.sh
leaving test02.sh
OUTPUT EXPECTED:
93
inside test01.sh
inside test02.sh
inside test03.sh
leaving test01.sh
leaving test02.sh
leaving test03.sh
Processing Done
The order of the echo commands are not that big of a deal, though if someone knows why they go 3,2,1, then 3,1,2, I wouldn't hate an explanation.
However, I am not getting that final Processing Done. Anyone have any clue why the final echo back in /my/scripts/dir/directoryPercentFull.sh does not occur? I have purposefully not placed an & after the last exec statement, as I don't want what what is after the if/fi to run until all of it is finished processing.
/someDir/someOtherDir/test01.sh &
/someDir/someOtherOtherDir/test02.sh &
/someDir/yetAnotherDir/test03.sh
Get rid of all the execs. exec causes the shell process to be replaced by the given command, meaning the shell does not continue executing further commands.
The order of the echo commands are not that big of a deal, though if someone knows why they go 3,2,1, then 3,1,2, I wouldn't hate an explanation.
The printouts could come in any order. The three scripts are run in parallel processes so there's no telling which order they echo their printouts.

Run bash script in background by default

I know I can run my bash script in the background by using bash script.sh & disown or alternatively, by using nohup. However, I want to run my script in the background by default, so when I run bash script.sh or after making it executable, by running ./script.sh it should run in the background by default. How can I achieve this?
Self-contained solution:
#!/bin/sh
# Re-spawn as a background process, if we haven't already.
if [[ "$1" != "-n" ]]; then
nohup "$0" -n &
exit $?
fi
# Rest of the script follows. This is just an example.
for i in {0..10}; do
sleep 2
echo $i
done
The if statement checks if the -n flag has been passed. If not, it calls itself with nohup (to disassociate the calling terminal so closing it doesn't close the script) and & (to put the process in the background and return to the prompt). The parent then exits to leave the background version to run. The background version is explicitly called with the -n flag, so wont cause an infinite loop (which is hell to debug!).
The for loop is just an example. Use tail -f nohup.out to see the script's progress.
Note that I pieced this answer together with this and this but neither were succinct or complete enough to be a duplicate.
Simply write a wrapper that calls your actual script with nohup actualScript.sh &.
Wrapper script wrapper.sh
#! /bin/bash
nohup ./actualScript.sh &
Actual script in actualScript.sh
#! /bin/bash
for i in {0..10}
do
sleep 10 #script is running, test with ps -eaf|grep actualScript
echo $i
done
tail -f 10 nohup.out
0
1
2
3
4
...
Adding to Heath Raftery's answer, what worked for me is a variation of what he suggested such as this:
if [[ "$1" != "-n" ]]; then
$0 -n & disown
exit $?
fi

string comparison is shell script

I have a scenario to copy file from one server to another, for that i need to check any existing scp is in progress, have wrote a sample shell script but the condition is not being met even though syntax is correct, the main problem here is the output of ps command will gets stored in variable scpstat and the same compared for matching string in if statement, here I'm getting the output of the variable is different from executing outside of the script. can see it is formatted different in script execution when executing sh -x scpsamp.sh, why there is "sh" appended to the output, but while comparing without ps and assigning as scpstat='scp' i can able to get the condition correct, am i doing anything wrong while getting output in to the variable. please help
#!/bin/sh
scpstat=`ps -ef | grep scp | egrep -v 'grep|ssh' | awk '{print $8}')`
if [ "$scpstat" = "scp" ];
then
echo "SCP is in progress"
else
echo "No SCP in progress"
fi
sh -x output
It's notoriously difficult to extract information from the output of ps. If your system has pgrep, it's much easier:
if pgrep scp >/dev/null
then
echo "SCP is in progress"
else
echo "No SCP in progress"
fi

Creating a for loop in a trap doesn't work in Shell script

I have been trying to create a trap in a script to basically create some logs of a script that has been running in the background.
Whenever I introduce a for loop in the trap, the script stops doing what it is supposed to do:
trap 'terminate' 10
...
write_log(){
local target=$1
local file="/tmp/"$target"_log.txt"
local lines=$(cat /tmp/"$target"_log.txt | wc -l)
printf "Log for $target\n" >> "log.txt" # This line is printed
for ((i=1;i<=$lines;i++)); # Nothing in this loop happens
do
local start_date=$(date -d "$(sed -n ""$i"p") $file | cut -f1")
local end_date=$(date -d "$sed -n ""$i"p") $file | cut -f2")
printf "Logged in $start_date, logged out $end_date" > "log.txt"
done
}
terminate(){
for target
do
echo "In the for loop!"
end_session "$target"
write_log "$target"
done
exit 0
}
When I run my script in the background and kill it with
kill -10 (process_id)
the script stops, and starts doing the cleanup, until the point where it finds a for loop. When I remove the for loop in terminate() and instead do individual calls to end_session() and write_log(), end_session() works just fine, and write_log() works fine--until it reaches the for loop.
I am probably missing something basic, but I have looked at this for a while now and can't seem to figure out what is happening. Is there any limitation to for loops in traps?
No arguments are passed to terminate when it is invoked by the trap, so its loop executes zero times (because for target; do …; done is a shorthand for for target in "$#"; do …; done, and in a function, "$#" is the list of arguments to the function, not to the shell script as a whole).
If that's not what you want to have happen, you have to arrange to pass the relevant arguments to terminate in the trap. For example, you could pass all the arguments to the script via a global array:
args=( "$#" )
and inside terminate:
for target in "${args[#]}"
However, what's best depends on what you want to achieve.
The function is hanging because the parentheses are messed up in the date commands. Try this:
local start_date=$(date -d "$(sed -n ${i}p "$file" | cut -f1)")
local end_date=$(date -d "$(sed -n ${i}p "$file" | cut -f2)")

Resources