Shell script: fire a command if system time is equal to given time - linux

I am very new to shell scripting.
The script should fire a command if the given time as command line argument is equal to the system time, else it should wait(poll) for the given time.
I started with very basics, but i am stuck here only:-(
#!/bin/sh
now=$(date +%k%M)
cur="055" # should be given as command line arg
if ($now == $cur)
then
echo "Fire command here"
else
echo "poll for time"
fi
When i execute the script:
./script.sh: line 5: 055: command not found
poll for time
Thanks for the help.

I think the above is just a small syntax error, instead of:
if ($now == $cur)
You may want to do this:
if [ $now -eq $cur ] #very basic comparison here, you may want to have a
#look at the bash comparisons
Update
Could you change the variable to,
$cur=$(date +%H%M)
And in case the input is not provided by you, you should remove the space in front
of the $now
now=$(echo $now | sed 's/\s//g') #this removes the spaces in the input

You can run a program # a particular time with :
crontab -e
and
0 14 * * * command
to run command # 14 PM (by example)

begin="`date '+%s'`"
final=... #should be converted to seconds since epoch...
sleep $((final - begin))
exec_your_command

The problem you described seems to be exactly what crontab is designed to handle, from wikipedia "Cron is driven by a crontab (cron table) file, a configuration file that specifies shell commands to run periodically on a given schedule."
Here is a quick reference, it is reletively barebones, but should be enough to determine if it meets your needs.

Use following code
if [ $now == $cur ]

Related

How to call another shell script from a shell script in Linux

I am trying to create one wrapper script to trigger the parent script at 6AM only. But it is not properly working. It always showing Do Nothing and else part is looping without exit. Can any one help?
I want to check if the time is 6 AM and also need to check the string from text file(status). if both conditions are satisfied my parent script should execute via this wrapper script.
Below is the script
path= $(cat /home/avj/)
mode= $(cat /home/avj/status)
checktime="060000"
echo $checktime
echo $currentTime
while true
do
currentTime=date +"%H%M%S"
if [[ $currentTime -eq $checktime && $status == running ]];
then
sh &path/parent.sh
else
echo Do Nothing
fi
done
Usually on Linux, you use crontab for this kind of scduled tasks. But you have to specify the time when you "set up the timer" - so if you want it to be configured in the file itself, you will have to create some mechanism for this.
For example, you can add crontab
30 1 * * 5 /path/to/script/script.sh
Will execute the script every Friday at 1: 30 (AM) here:
30 is minutes
1 is an hour
the next 2 * are the day of month and month (in that order), and the 5th is the day of the week

cron script needs conditional to run

I have two python scripts that Im trying to run on my server
I currently have process_one running through a cron job every five minutes I want to add the second script to the cron job.
I was told by the freelancer that both programs can run automatically by writing a shell script. If process_one generates data in its output_folder (i.e.
process_two's input_folder) then it will return system status "0" (OK) to the operating system, otherwise it returns a
ERROR signal - even in the case of "no errors, yet nothing new produced".
Im at a loss Ive never written shell scripts before. Im looking on here and else where but I dont know how to write this. Any help would be appreciated
/path/to process1/process_one && /path/to process2/process_two
What you have for the cron job is correct, process one will run and if successful process_two will run. The only thing that is missing is for process_two to check for new data in the process_one output directory before it runs.
I would suggest that you use a few lines at the top of process_two python script to check for recent data and exit if not found. Either you can modify the python script itself to do this, or write a bash wrapper as process_two that simply calls the python script after checking for recent data.
py
import os.path, time
fileCreation = os.path.getctime(filePath)
now = time.time()
fivemin_ago = now - 300
if fileCreation < fivemin_ago:
sys.exit "data was older than five minutes"
bash
NOW=$(date +%s)
MODIFIED=$(date -d "$(stat FILEPATH | grep Modify | awk '{print $2" "$3}')" +%s)
if [ $NOW -gt $[$MODIFIED+300] ];then
echo "data was older than five minutes"
exit 1
else
process_two.py
fi
The best way will make a third file where you can call the first script and get the return after the return you run or not the second script, it will be something like.
#!/usr/bin/env bash
variable=$(download "something")
if [-f "../path/your/file.pdf" ]; then
run here your second command // if file exists run it
fi

Understand when to use spaces in bash scripts

I wanted to run a simple bash timer and found this online (user brent7890)
#!/usr/bin/bash
timer=60
until [ "$timer" = 0 ]
do
clear
echo "$timer"
timer=`expr $timer - 1`
sleep 1
done
echo "-------Time to go home--------"
I couldn't copy and paste this code because the server is on another network. I typed it like this (below) and got an error on the line that starts with "until".
#!/usr/bin/bash
timer=60
#Note I forgot the space between [ and "
until ["$timer" = 0 ]
do
clear
echo "$timer"
timer=`expr $timer - 1`
sleep 1
done
echo "-------Time to go home--------"
Where is spacing like this documented? It seems strange that it matters. Bash scripts can be confusing, I want to understand why the space is important.
There are several rules, two basic of that are these:
You must separate all arguments of a command with spaces.
You must separate a command and the argument, that follows after, with a space.
[ here is a command (test).
If you write ["$timer" that means that you start command [60,
and that is, of course, incorrect. The name of the command is [.
The name of the command is always separated from the rest of the command line with a space. (you can have a command with a space in it, but in this case you must write the name of the command in "" or '').

How to show line number when executing bash script

I have a test script which has a lot of commands and will generate lots of output, I use set -x or set -v and set -e, so the script would stop when error occurs. However, it's still rather difficult for me to locate which line did the execution stop in order to locate the problem.
Is there a method which can output the line number of the script before each line is executed?
Or output the line number before the command exhibition generated by set -x?
Or any method which can deal with my script line location problem would be a great help.
Thanks.
You mention that you're already using -x. The variable PS4 denotes the value is the prompt printed before the command line is echoed when the -x option is set and defaults to : followed by space.
You can change PS4 to emit the LINENO (The line number in the script or shell function currently executing).
For example, if your script reads:
$ cat script
foo=10
echo ${foo}
echo $((2 + 2))
Executing it thus would print line numbers:
$ PS4='Line ${LINENO}: ' bash -x script
Line 1: foo=10
Line 2: echo 10
10
Line 3: echo 4
4
http://wiki.bash-hackers.org/scripting/debuggingtips gives the ultimate PS4 that would output everything you will possibly need for tracing:
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
In Bash, $LINENO contains the line number where the script currently executing.
If you need to know the line number where the function was called, try $BASH_LINENO. Note that this variable is an array.
For example:
#!/bin/bash
function log() {
echo "LINENO: ${LINENO}"
echo "BASH_LINENO: ${BASH_LINENO[*]}"
}
function foo() {
log "$#"
}
foo "$#"
See here for details of Bash variables.
PS4 with value $LINENO is what you need,
E.g. Following script (myScript.sh):
#!/bin/bash -xv
PS4='${LINENO}: '
echo "Hello"
echo "World"
Output would be:
./myScript.sh
+echo Hello
3 : Hello
+echo World
4 : World
Workaround for shells without LINENO
In a fairly sophisticated script I wouldn't like to see all line numbers; rather I would like to be in control of the output.
Define a function
echo_line_no () {
grep -n "$1" $0 | sed "s/echo_line_no//"
# grep the line(s) containing input $1 with line numbers
# replace the function name with nothing
} # echo_line_no
Use it with quotes like
echo_line_no "this is a simple comment with a line number"
Output is
16 "this is a simple comment with a line number"
if the number of this line in the source file is 16.
This basically answers the question How to show line number when executing bash script for users of ash or other shells without LINENO.
Anything more to add?
Sure. Why do you need this? How do you work with this? What can you do with this? Is this simple approach really sufficient or useful? Why do you want to tinker with this at all?
Want to know more? Read reflections on debugging
Simple (but powerful) solution: Place echo around the code you think that causes the problem and move the echo line by line until the messages does not appear anymore on screen - because the script has stop because of an error before.
Even more powerful solution: Install bashdb the bash debugger and debug the script line by line
If you're using $LINENO within a function, it will cache the first occurrence. Instead use ${BASH_LINENO[0]}

Bash script to capture input, run commands, and print to file

I am trying to do a homework assignment and it is very confusing. I am not sure if the professor's example is in Perl or bash, since it has no header. Basically, I just need help with the meat of the problem: capturing the input and outputting it. Here is the assignment:
In the session, provide a command prompt that includes the working directory, e.g.,
$./logger/home/it244/it244/hw8$
Accept user’s commands, execute them, and display the output on the screen.
During the session, create a temporary file “PID.cmd” (PID is the process ID) to store the command history in the following format (index: command):
1: ls
2: ls -l
If the script is aborted by CTRL+C (signal 2), output a message “aborted by ctrl+c”.
When you quit the logging session (either by “exit” or CTRL+C),
a. Delete the temporary file
b. Print out the total number of the commands in the session and the numbers of successful/failed commands (according to the exit status).
Here is my code so far (which did not go well, I would not try to run it):
#!/bin/sh
trap 'exit 1' 2
trap 'ctrl-c' 2
echo $(pwd)
while true
do
read -p command
echo "$command:" $command >> PID.cmd
done
Currently when I run this script I get
command read: 10: arg count
What is causing that?
======UPDATE=========
Ok I made some progress not quite working all the way it doesnt like my bashtrap or incremental index
#!/bin/sh
index=0
trap bashtrap INT
bashtrap(){
echo "CTRL+C aborting bash script"
}
echo "starting to log"
while :
do
read -p "command:" inputline
if [ $inputline="exit" ]
then
echo "Aborting with Exit"
break
else
echo "$index: $inputline" > output
$inputline 2>&1 | tee output
(( index++ ))
fi
done
This can be achieved in bash or perl or others.
Some hints to get you started in bash :
question 1 : command prompt /logger/home/it244/it244/hw8
1) make sure of the prompt format in the user .bashrc setup file: see PS1 data for debian-like distros.
2) cd into that directory within you bash script.
question 2 : run the user command
1) get the user input
read -p "command : " input_cmd
2) run the user command to STDOUT
bash -c "$input_cmd"
3) Track the user input command exit code
echo $?
Should exit with "0" if everything worked fine (you can also find exit codes in the command man pages).
3) Track the command PID if the exit code is Ok
echo $$ >> /tmp/pid_Ok
But take care the question is to keep the user command input, not the PID itself as shown here.
4) trap on exit
see man trap as you misunderstood the use of this : you may create a function called on the catched exit or CTRL/C signals.
5) increment the index in your while loop (on the exit code condition)
index=0
while ...
do
...
((index++))
done
I guess you have enough to start your home work.
Since the example posted used sh, I'll use that in my reply. You need to break down each requirement into its specific lines of supporting code. For example, in order to "provide a command prompt that includes the working directory" you need to actually print the current working directory as the prompt string for the read command, not by setting the $PS variable. This leads to a read command that looks like:
read -p "`pwd -P`\$ " _command
(I use leading underscores for private variables - just a matter of style.)
Similarly, the requirement to do several things on either a trap or a normal exit suggests a function should be created which could then either be called by the trap or to exit the loop based on user input. If you wanted to pretty-print the exit message, you might also wrap it in echo commands and it might look like this:
_cleanup() {
rm -f $_LOG
echo
echo $0 ended with $_success successful commands and $_fail unsuccessful commands.
echo
exit 0
}
So after analyzing each of the requirements, you'd need a few counters and a little bit of glue code such as a while loop to wrap them in. The result might look like this:
#/usr/bin/sh
# Define a function to call on exit
_cleanup() {
# Remove the log file as per specification #5a
rm -f $_LOG
# Display success/fail counts as per specification #5b
echo
echo $0 ended with $_success successful commands and $_fail unsuccessful commands.
echo
exit 0
}
# Where are we? Get absolute path of $0
_abs_path=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )
# Set the log file name based on the path & PID
# Keep this constant so the log file doesn't wander
# around with the user if they enter a cd command
_LOG=${_abs_path}/$$.cmd
# Print ctrl+c msg per specification #4
# Then run the cleanup function
trap "echo aborted by ctrl+c;_cleanup" 2
# Initialize counters
_line=0
_fail=0
_success=0
while true
do
# Count lines to support required logging format per specification #3
((_line++))
# Set prompt per specification #1 and read command
read -p "`pwd -P`\$ " _command
# Echo command to log file as per specification #3
echo "$_line: $_command" >>$_LOG
# Arrange to exit on user input with value 'exit' as per specification #5
if [[ "$_command" == "exit" ]]
then
_cleanup
fi
# Execute whatever command was entered as per specification #2
eval $_command
# Capture the success/fail counts to support specification #5b
_status=$?
if [ $_status -eq 0 ]
then
((_success++))
else
((_fail++))
fi
done

Resources