sh script under debian time dependence - bash

I've build very simple sh script with curl "url" action ( lights control ) for example when I start playing movie lighits are going off, when movie pause are turnig on. I wanna ask You for help how to build this script...
I want this to check what time is and than if it's day light time for example till 4pm lights will stay turned OFF but after 4 pm lights will response.
I did little research and found time checking command: HOUR=$(date +"%k")
So if I'm thinking right what is impossibl :) I need something like:
#!/bin/sh
HOUR=$(date +"%k")
if (( HOUR >= 7am && HOUR <= 4pm ))
curl "URL 1 lights control not included"
else
curl "URL 2 lights control incuded"
fi
Thank You in advance and sorry for my English.

Good old case to the rescue.
#!/bin/sh
case $(date +"%H") in
0[7-9] | 1[0-5] ) url="URL 1 lights control not included" ;;
* ) url="URL 2 lights control incuded" ;;
esac
curl "$url"
The expression matches 07:00:00 through 15:59:59; if you intend for it to match until 16:59:59, the change should be obvious.

Separate light actions and movie actions.
When pausing movie, check if current hour is greater than or equal to enable_lights_at. If yes, turn lights on and pause the movie. When playing movie - first turn the lights off.
#!/bin/bash
#
enable_lights_at=16
lights_turn_off() {
echo "Turning lights OFF";
curl "URL LIGHTS OFF"
}
lights_turn_on() {
echo "Turning lights ON";
curl "URL LIGHTS ON"
}
movie_play() {
echo "Playing movie";
lights_turn_off;
curl "URL PLAY MOVIE"
}
movie_pause() {
echo "Pausing movie";
current_hour=$(date "+%k")
if [ "$current_hour" -ge "$enable_lights_at" ];
then
lights_turn_on;
fi
curl "URL PAUSE MOVIE"
}
case "$1" in
'play')
movie_play;
;;
'pause')
movie_pause;
;;
*)
echo "Usage: $0 {play|pause}"
;;
esac
Worth checking:
http://tldp.org/LDP/abs/html/comparison-ops.html

Related

Raspberry Pi screensaver/DMPS on/off to trigger shell script on change

I've got a touch screen without backlight control and and turning off the HDMI-output just brings up a "no signal" placeholder on the screen.
I've soldered a octocoupler to the power toggle to control it via the GPIO-pins and that works fine.
What I would like to do is to toggle a shell script (screen_toggle.sh) everytime the Pi changes DPMS state. I.e as soon as DMPS blanks the screen the screen_toggle.sh would be triggered, and as soon as mouse (touch) input is registered screen_toggle.sh would be triggered again to wake the screen.
Anyone with ideas on how to get this working?
For anyone coming here looking for a solution.
Got around to fix it by doing the following. screen_switch.sh calls the GPIO in the Pi in my case but could do what ever someone would want.
#!/bin/bash
idletime=60000 # in milliseconds
screen_toggle=1
while true; do
idle=`xprintidle`
#echo $idle >> /home/pi/idle.log
if [ "$idle" -gt "$idletime" ] && [ "$screen_toggle" == 1 ]
then
screen_toggle=0
source /home/pi/screen_switch.sh
echo "Turned off" >> /home/pi/screen_check.log
elif [ "$idle" -lt "$idletime" ] && [ "$screen_toggle" == 0 ]
then
screen_toggle=1
source /home/pi/screen_switch.sh
echo "Turned on" >> /home/pi/screen_check.log
fi
sleep 1
done

How do I chain multiple user prompts together with the ability to go back a prompt?

I am wondering how I can make a bash script that has multiple menus in it.
For example, here's what the user would see upon running it:
Type the number of choosing:
1-play
2-load
3-exit
1
What is your name:
::prev::
Type the number of choosing:
1-play
2-load
3-exit
1
What is your name:
Brad
Where are you from, Brad?
Pennsylvania
What is your favourite colour?
1-blue
2-red
3-green
4-grey
5-magenta
,sdfhljalk:J;
What is your favourite colour?
1-blue
2-red
3-green
4-grey
5-magenta
2
What is your favourite toy?
train
What would you like on your sandwich?
::prev::
What is your favourite toy?
~`!##$%^& * ()_+=-{}[]|\"':;?/>.<,
What is your favourite toy?
::exit::
Exiting....
I apologize for it being long, I just want to cover all bases for the new game I'm going to be making. I want this to be the question to end all questions.
I want to be able to type ::prev:: wherever I am and have it go back to the previous question, and I'd like ::exit:: to exit the script wherever it is. Also, I'd like unrecognized input during questions with numbered responses to just reload the question without continuing, and for input containing characters that may cause a script break (something like :;!## ...) to reload the question instead of breaking.
Any help is greatly appreciated!
By the way, I'm using OS X Yosemite
First thing to do in this situation is to try and think of how, generally, you could implement something like this. Probably the biggest addition to complexity is using ::prev:: to go back a question. This means we need to represent the application state in some way such that we can move forward or backward.
Luckily, this is pretty simple: it's basically just an implementation of a stack that we need. Some visuals:
...
<--pop-- <--pop-- Location prompt <--pop-- ...
Name prompt Name prompt ...
Main menu --push-> Main menu --push-> Main menu --push-> ...
This also means each individual piece of the program needs to be self-contained. We can easily do this in shell scripting with functions.
So we need several pieces:
Function which displays a menu and allows the user to choose a value.
Function which displays a text prompt and allows the user to choose a value.
Function which manages a stack that represents the state of the program.
Individual functions for each piece of the program.
Let's first write our menu prompt function. This part is pretty easy. Bash will do most of the work using the select loop, which prints a menu for us. We'll just wrap it so that we can handle custom logic, like expecting ::exit:: or ::prev:: and some pretty-printing.
function show_menu {
echo "$1" # Print the prompt
PS3='> ' # Set prompt string 3 to '> '
select selection in "${menu_items[#]}" # Print menu using the menu_items array
do
if [[ "$REPLY" =~ ^(::exit::|::prev::)$ ]]; then
# If the user types ::exit:: or ::prev::, exit the select loop
# and return 1 from the function, with $selection containing
# the command the user entered.
selection="$REPLY"
return 1
fi
# $selection will be blank if the user did not choose a valid menu item.
if [ -z "$selection" ]; then
# Display error message if $selection is blank
echo 'Invalid input. Please choose an option from the menu.'
else
# Otherwise, return a success return code.
return 0
fi
done
}
We can now use this function like so:
menu_items=('Item 1' 'Item 2' 'Item 3')
if ! show_menu 'Please choose an item from the menu below.'; then
echo "You entered the command $selection."
fi
echo "You chose $selection."
Great! Now on to the next item on the agenda, writing the code that accepts text input from the user.
# Prompt for a required text value.
function prompt_req {
# do...while
while : ; do
# Print the prompt on one line, then '> ' on the next.
echo "$1"
printf '> '
read -r selection # Read user input into $selection
if [ -z "$selection" ]; then
# Show error if $selection is empty.
echo 'A value is required.'
continue
elif [[ "$selection" =~ ^(::exit::|::prev::)$ ]]; then
# Return non-success return code if ::exit:: or ::prev:: were entered.
return 1
elif [[ "$selection" =~ [^a-zA-Z0-9\'\ ] ]]; then
# Make sure input only contains a whitelist of allowed characters.
# If it has other characters, print an error and retry.
echo "Invalid characters in input. Allowed characters are a-z, A-Z, 0-9, ', and spaces."
continue
fi
# This break statement only runs if no issues were found with the input.
# Exits the while loop and the function returns a success return code.
break
done
}
Great. This function works similarly to the first:
if ! prompt_req 'Please enter a value.'; then
echo "You entered the command $selection."
fi
echo "You entered '$selection'."
Now that we have user input handled, we need to handle the program flow with our stack-managing function. This is fairly easy to implement in bash using an array.
When a part of the program runs and completes, it will ask the flow manager to run the next function. The flow manager will push the name of the next function onto stack, or rather, add it to the end of the array, and then run it. If ::prev:: is entered, it will pop the last function's name off of the stack, or remove the last element of the array, and then run the function before it.
Less talk, more code:
# Program flow manager
function run_funcs {
# Define our "stack" with its initial value being the function name
# passed directly to run_funcs
funcs=("$1")
# do...while
while : ; do
# Reset next_func
next_func=''
# Call the last function name in funcs.
if "${funcs[${#funcs[#]}-1]}"; then
# If the function returned 0, then no :: command was run by the user.
if [ -z "$next_func" ]; then
# If the function didn't set the next function to run, exit the program.
exit 0
else
# Otherwise, add the next function to run to the funcs array. (push)
funcs+=("$next_func")
fi
else
# If the function returned a value other than 0, a command was run.
# The exact command run will be in $selection
if [ "$selection" == "::prev::" ]; then
if [ ${#funcs[#]} -lt 2 ]; then
# If there is only 1 function in funcs, then we can't go back
# because there's no other function to call.
echo 'There is no previous screen to return to.'
else
# Remove the last function from funcs. (pop)
unset funcs[${#funcs[#]}-1]
fi
else
# If $selection isn't ::prev::, then it's ::exit::
exit 0
fi
fi
# Add a line break between function calls to keep the output clean.
echo
done
}
Our run_funcs function expects:
to be called with the name of the first function to run, and
that each function that runs will output the name of the next function to run to next_func if execution of the program must proceed.
Alright. That should be pretty simple to work with. Let's actually write the program now:
function main_menu {
menu_items=('Play' 'Load' 'Exit')
if ! show_menu 'Please choose from the menu below.'; then
return 1
fi
if [ "$selection" == 'Exit' ]; then
exit 0
fi
if [ "$selection" == 'Load' ]; then
# Logic to load game state
echo 'Game loaded.'
fi
next_func='prompt_name'
}
function prompt_name {
if ! prompt_req 'What is your name?'; then
return 1
fi
name="$selection"
next_func='prompt_location'
}
function prompt_location {
if ! prompt_req "Where are you from, $name?"; then
return 1
fi
location="$selection"
next_func='prompt_colour'
}
function prompt_colour {
menu_items=('Blue' 'Red' 'Green' 'Grey' 'Magenta')
if ! show_menu 'What is your favourite colour?'; then
return 1
fi
colour="$selection"
next_func='prompt_toy'
}
function prompt_toy {
if ! prompt_req 'What is your favourite toy?'; then
return 1
fi
toy="$selection"
next_func='print_player_info'
}
function print_player_info {
echo "Your name is $name."
echo "You are from $location."
echo "Your favourite colour is $colour."
echo "Your favourite toy is $toy."
# next_func is not set, so the program will exit after running this function.
}
echo 'My Bash Game'
echo
# Start the program, with main_menu as an entry point.
run_funcs main_menu
Everything is in order now. Let's try out our program!
$ ./bash_game.sh
My Bash Game
Please choose from the menu below.
1) Play
2) Load
3) Exit
> ::prev::
There is no previous screen to return to.
Please choose from the menu below.
1) Play
2) Load
3) Exit
> 2
Game loaded.
What is your name?
> Stephanie
Where are you from, Stephanie?
> ::prev::
What is your name?
> Samantha
Where are you from, Samantha?
> Dubl*n
Invalid characters in input. Allowed characters are a-z, A-Z, 0-9, ', and spaces.
Where are you from, Samantha?
> Dublin
What is your favourite colour?
1) Blue
2) Red
3) Green
4) Grey
5) Magenta
> Aquamarine
Invalid input. Please choose an option from the menu.
> 8
Invalid input. Please choose an option from the menu.
> 1
What is your favourite toy?
> Teddie bear
Your name is Samantha.
You are from Dublin.
Your favourite colour is Blue.
Your favourite toy is Teddie bear.
And there you have it.

BASH script checking log files for current and previous month

I have been working on this on and off for the last two months, and despite how many times I look at it, I can't make it work.
This script checks daily log files for a user defined variable, so they don't have to look through every one manually. It worked great checking the current month, but if the user wants to check back 20 days, and today is the 12th of this month, I wanted to be able to then go back to the previous month (not look for the log file with a date of 20150399 and so on). I have checked the logic for my date/day computations, and they seem okay (if there is a better way to do that in BASH, I am open to suggestions). What happens when I try to debug is unexpected end of file. I am somewhat new to writing scripts that contain more than 20 or so lines, but I just can't come up with what I am missing.
I have tried various fixes, to no avail, but I think this is the last iteration.
Ideas?
#!/bin/bash
########################################################
# multi_log_chk.sh
# This script will take input from the user and report which
# CyberFusion MFT logs contain what the user is looking for.
# Hopefully this will save the user having to search through every
# stinking log file to find what they are looking for.
# 20150406 pxg007 started typing
# 20150413 pxg007 added && comparison for back out (line 28)
# added message for no entries found (line 32, 38, 48-52)
# Added some further description (line 16)
# 20150424 pxg007 Added logic to calculate previous month and if necessary, year. (Lines 16-24, 60-78 )
#
########################################################
currDate=`date +%d%B%C%y`
currDay=`date +%d`
currMnth=`date +%m`
currYear=`date +%C%y`
case $currMnth in #Let's establish number of days for previous month
05 | 07 | 10 | 12 ) lastMnthD=30;;
01 |02 | 04 | 06 | 09 | 08 | 11 ) lastMnthD=31;;
03 ) lastMnthD=28;; ##and screw leap year
esac
if [ $currMnth -eq 01 ]; then ##accounting for January
lastMnth=12
else
lastMnth=$((currMnth-1))
fi
if [ $lastMnth -eq 12 ]; then ## accounting for Dec of previous year
lastMnthYr=$((currYear-1))
else
lastMnthYr=$currYear
fi
echo "This script will find entries for your query in whatever available MFT logs you request."
echo " "
echo "For instance - how many log files have transfer entries with \"DOG\" in them?"
echo " "
echo "I also will also give an estimate of how many transfers per log file contain your query, give or take a couple."
echo " "
echo "This search is case sensitive, so \"DOG\" is *** NOT *** the same as \"dog\""
echo " "
read -p "What text you are looking for? Punctuation is okay, but no spaces please. " looking ### what we want to find
echo " "
echo "Today's date is: $currDate."
echo " "
read -p "How many days back do you want to search(up to 25)? " daysBack ### How far back we are going to look
if [ "$daysBack" == 0 ] && [ "$daysBack" >> 25 ]; then
echo "I said up to 25 days. We ain't got more than that!"
exit 1
fi
echo " "
echo "I am going to search through the last $daysBack days of log files for:\"$looking\" "
echo " "
read -p "Does this look right? Press N to quit, or any other key to continue: " affirm
if [ "$affirm" = N ] && [ "$affirm" = n ]; then ###Yes, anything other than "N" or "n" is a go
echo "Quitter!"
exit 1
else
nada=0 ### Used to test for finding anything
backDate=$((currDay-daysBack)) ### current month iterator (assuming query covers only current month)
if (("$daysBack" => "$currDay")); then ## If there are more logs requested than days in the month...
lastMnthCnt=$((daysBack-currDay)) ### how many days to check last month
lastMnthStrt=$((lastMnthD-lastMnthCnt)) ## last month start and iterator
backDate=$(currDay-(daysBack-lastMnthCnt)) # Setting the iterator if we have to go back a month
while (("$lastMnthStrt" <= "$lastMnthD" )); do
foundIt=$(grep "$looking" /CyberFusion/log/Log.txt."$lastMnthYr$lastMnth$lastMnthStrt" | parsecflog | wc -l )
howMany=$((foundIt/40+1)) ### Add one in case there are less than 40 lines in the record.
if (("$foundIt" > 0))
then
nada=$((nada+1))
echo "Log.txt.$lastMnthYr$lastMnth$lastMnthStrt contains $looking in approximately $howMany transfer records."
lastMnthStrt=$((lastMnthStrt+1))
echo " "
else
lastMnthStrt=$((lastMnthStrt+1))
fi
fi
backDate=$((currDay-daysBack)) ### current month iterator (assuming query covers only current month)
while (("$backDate" <= "$currDay")); do
foundIt=$(grep "$looking" /CyberFusion/log/Log.txt."$backDate" | parsecflog | wc -l )
howMany=$((foundIt/40+1)) ### Add one in case there are less than 40 lines in the record.
if (("$foundIt" > 0))
then
nada=$((nada+1))
echo "Log.txt.$backDate contains $looking in approximately $howMany transfer records."
backDate=$((backDate+1))
echo " "
else
backDate=$((backDate+1))
fi
if [ "$nada" \< 1 ]
then
echo " "
echo "I found no entries for $looking in any log file."
fi
You are missing the keyword 'done' on lines 81 and 96 and also a final 'fi' keyword on the last line.
Also as others suggested you can do
date -d "20 days ago" +"%d%B%C%y"
to easily get dates in the past

Error while assigning a value in second case statement for interactive script

I am trying to write a user interactive script. I am doing it by letting the user type the values of the flags. My first case statement works fine but the second won't and I don't understand why? In the last two lines of this code I am suppose to see the values of my variables but I can only see the assigned value from the first statement and the second case statement give me no value. I have more case statements in my code but the first one is the only one that works. Do I need to do something in between statements?
echo "`tput bold`What machine was used?`tput sgr0`"
select Machine in "M1" "M2" "M3" "M4" "M5" "quit"
do
case $Machine in
M1) version=10;;
M2|M5) version=15;;
M4|M3) version=27;;
quit) exit;;
*) echo -e '\033[5;31;40mERROR: \033[0m\033[31;40mWrong option.\033[0m';;
esac
break
done
echo "`tput bold`Do you want to run default settings`tput sgr0`"
select settings in "yes" "no" "quit"
do
case $settings in
yes) run=1;;
no) run=0;;
quit) exit;;
*) echo -e '\033[5;31;40mERROR: \033[0m\033[31;40mWrong option.\033[0m';;
esac
break
done
echo "Version: $version"
echo "Default settings: $run"
This should be working fine. If you press 1 for each option, you get
Version: 10
Default settings: 1
Did you perhaps habitually press y instead of 1 to answer "yes"?

How do i achieve "read -i" in a different way?

I Have been looking on the internet but without finding a solution (hard to know what to serach for). I want a way to show "current value" on an input. Similar to what read -e -p "something: " -i "this" $variable does but in Busybox sh. As that option only became available in Bash4 which is not default. I will have to solve it another way. Not sure if this is possible..
read -p "Select by entering an number: " ANS
case $ANS in
1 ) ANS="%R | %a %d %b" ;;
2 ) ANS="%R, %a %d %b" ;;
3 ) read -p "Enter a custom string (ex. %R): " ANS ;;
4 ) ANS="%R" ;;
* ) read -p "Just answer with a number between 1 to 4. Aborting!" end; exit 0 ;;
esac
What i want is that case #3 will show the current value of the file. Ex. If the file has %R as current value. Then that is what i want it to show on input for user to interactively change it.
Until you can give us examples of what you want the programme to take as an 'input' and then give as an 'output', I suggest you read TLPD's section on 'read'

Resources