Can someone help and tell me why this isn't working?
I have checked the script and solved some problems but it still doesn't works fine and I can't find the mistake.
#!/bin/bash
#variabelen
IP="192.168.0."
array=($#)
#functies
What's wrong with the array? My linux told me that there is a syntax error on line 12 so with that array but he doesn't tell me what.
function Sorteer(){
array=($(printf '%s\n' "$#"|sort -nu))
for i in ${array[#]};do
ping -c -1 "IP"$i
done
}
function Telbij(){
# given number $i +200
b=$(( $i + 200 ))
if (( b > 255 ))
then
echo "Neem kleiner getal";
else
ping -c 1 "IP"$b;
fi
}
function XXYY() {
#ping 65-68 = ping 65 66 67 68
start=${1%-*}
end=${1#*-}
for ((i=start;i<=end;i++));do
ping -c 1 "$IP"$i
done
}
The mistake is in the if else function: http://prntscr.com/7gr8yf
But I don't know what that means: "The mentioned parser error was in this else clause."
if [ "$#" -eq 0 ]; then
echo "Er moet minimaal 1 parameter worden meegegeven "
exit 0
else
case
-h -help ) echo "Geef de laatste cijfers van het IP-adres van de pc's om te testen.";;
XX-YY ) XXYY;;
-t ) Telbij;;
- sort ) Sorteer;;
esac
fi
done
Don't know what's specifically not working but,
in Sorteer function you should double quote array expansions to avoid re-splitting elements.
Try change to following:
function Sorteer(){
array=($(printf '%s\n' "$#"|sort -nu))
for i in "${array[#]}";do
ping -c -1 "IP"$i
done
}
Now your case operator should be like:
case $some_value in
-help ) echo "Geef de laatste cijfers van het IP-adres van de pc's om te testen.";;
XX-YY ) XXYY;;
-t ) Telbij;;
-sort ) Sorteer;;
esac
This will fix your if issue as well
Related
Hi I have made an automatic light switch program destined for my pi, it tracks if my phone is on wifi network it works but its not very fast. If i speed it up I either receive lots of false positives or doesnt work I have found and only changed a tiny bit of code from other examples online. I'm still learning.
so I've got two lots of code one bash and one python.
python uses arp-scan
and bash uses ip neighbor and ping with seem to be more reliable
so can someone help me mash the bash code into python and make it use {arp-scan, ip neighbor, ping and maybe bluetooth as well
I would like to add some settings like
ensure the lights dont get turned on in day time hours
somehow track the gpio high low toggle in a better way
adding bluetooth scan that actually work when android dev is sleeping (screen off)
at the moment i have it running on the pi as a web site for testing here is a screenshot of my pi site
python code example
#!/usr/bin/python3
import RPi.GPIO as GPIO
import subprocess
from time import sleep
is_home = False
home_run_count = 0
out_run_count = 0
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)
if __name__ == '__main__':
while True:
p = subprocess.Popen("arp-scan -l -r 6 | grep MAC:MAC:MAC",stdout=subprocess.PIPE, shell=True)
(output, err) = p.communicate()
p_status = p.wait()
if output:
#print("Android device is connected to your network!")
is_home = True
if p.returncode != 0:
#print("The device is not present!")
is_home = False
#home_run_count = 0
#out_run_count -= 1
if is_home is True and home_run_count < 1:
#print("lights on!")
#GPIO.setmode(GPIO.BCM)
#GPIO.setup(17, GPIO.OUT)
GPIO.output(17, True)
sleep(0.5);
GPIO.output(17, False)
home_run_count += 1
out_run_count = 0
is_home = True
if is_home is False and out_run_count < 1:
#print("lights off!")
#GPIO.setmode(GPIO.BCM)
#GPIO.setup(17, GPIO.OUT)
GPIO.output(17, True)
sleep(0.5);
GPIO.output(17, False)
out_run_count += 1
home_run_count = 0
is_home = False
enter code here
Bash script code
#!/bin/bash
# A script to do something when Phone returns Home.
mac="some mac addy" # Your phone mac address
ip_addr="" # Leave blank or ip for test
network="some ip addy" # Your network (Class C only)
range="90 100" # ip address possible range
pgm() {
echo "switching lights "
echo "1" > /sys/class/gpio/gpio17/value
sleep 0.5s
echo "0" > /sys/class/gpio/gpio17/value
}
#-----Rpi-Mod----
echo "17" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio17/direction
#-----End of Rpi mod first section-------
start=$(echo "$range" | cut -d " " -f1)
stop=$(echo "$range" | cut -d " " -f2)
network=$(echo "$network" | cut -d. -f1-3)
echo "Start $(date)"
while [ 1 ]; do
cnt=0
fail=0
[ "$ip_addr" ] || while [ ! "$ip_addr" ]; do
for x in $(seq "$start" "$stop"); do
(junk=$(ping -c1 -W1 "$network"."$x") & )
wait
done
sleep 8
ip_addr=$(ip neighbor | grep "$mac" | cut -d " " -f1)
((cnt++))
if (( $cnt > 15 )); then
cnt=0
echo "--- Phone not Home $(date)"
#sleep 300 # 5 minutes
fi
if [ "$ip_addr" ]; then
echo "--- Phone is Home, Count = $cnt, Date = $(date)"
echo "Phone ip = $ip_addr mac = $mac"
fi
done
while [ "$ip_addr" ]; do
junk="$(ping -c1 -W1 $ip_addr)"
sleep 8
home_nw="$(ip neighbor | grep $ip_addr | cut -d ' ' -f 1,5,6)"
echo "$home_nw - $(date)"
is_home=$(echo "$home_nw" | cut -d " " -f3)
if [ "$is_home" == "REACHABLE" ] && (( "$fail" >= 3 )); then
echo "--- Phone returned Home - $(date)"
pgm
fi
[ "$is_home" == "REACHABLE" ] && fail=0
mac_stat=$(echo "$home_nw" | cut -d " " -f2)
if [ "$mac_stat" == "FAILED" ]; then
(( "$fail" < 10 )) && ((fail++))
ip_test="$(ip neighbor | grep $mac | cut -d ' ' -f1)"
if [ "$ip_test" ]; then
[ "$ip_test" == "$ip_addr" ] || ip_addr=""
fi
if (( "$fail" == 3 )); then
echo "--- Phone not at Home $(date)"
pgm
fi
else
if [ "$mac_stat" != "$mac" ]; then
ip_addr=""
fi
fi
#sleep 300 # 5 minutes
done
done
I don't know enough to implement my changes but still learning so would appreciate some woking cot to try and in the process learn.
------------------------------------------------------ update -------------------------------------------------------------------
I tried to put code in the comment but it didn't work. I've sort of managed to get what I wanted. I modified the python script to call a new script (see below) because I was unable to get popen to run my function maybe it needs to be a class or clash, I'm open to suggestions.
def present():
with urllib.request.urlopen("http://blah.ip.blah/some.json") as url:
sleep(0.5);
data = json.loads(url.read().decode())
#print(data)
'MAC:MAC:MAC:' in data
So because I could not make the rest of the logic work i just stuck it in a new file like this
#!/usr/bin/python3
import urllib.request, json
from time import sleep
import os
try:
with urllib.request.urlopen("http://blah.ip.blah/some.json") as url:
sleep(0.5);
data = json.loads(url.read().decode())
#print(data)
'MAC:MAC:MAC:' in data
except KeyboardInterrupt:
os._exit(1)
but would love to combine it with the main light script as a function.
why does this not work ?
(output, err) = ( present() )
p_status = ( present() )
----------------------------------------------------------- end of update one -----------------------------------------------
I had some trouble getting the python loop to keep running when called from the site but it was an silly incorrect path issue, that's why I want to have it all on one file
----------------------------------------------------------- end of update two ---------------------------------------------
I've asked a similar question if anyone is interested
I wrote a bash script that uses fping that detects devices entering/exiting a LAN It could easily be adapted to turn lights on and off.
The code is here https://grymoire.wordpress.com/2019/12/09/using-bash-to-monitor-devices-entering-exiting-a-lan/
I am coding in bash ,using Ubuntu 18.04, and I am playing around with kdialog. I made a simple magic eight ball themed program and I am unable to close the input box and exit the program, instead I get stuck in a loop. This code was originally made in BASH dialog and I decided to change it to kdialog. Any help would be greatly appreciated. It is something simple that I am overlooking.
#!/bin/bash
#version 3
OUTPUT="TEMP.txt"
>$OUTPUT
while [ true ]
do
shuffle() {
local i tmp size max rand
size=${#array[*]}
max=$(( 32768 / size * size ))
for ((i=size-1; i>0; i--));
do
while (( (rand=$RANDOM) >= max ));
do :;
done
rand=$(( rand % (i+1) ))
tmp=${array[i]}
array[i]=${array[rand]}
array[rand]=$tmp
done
}
array=( 'It Is Certain'
'Without A Doubt'
'Maybe'
'Signs Point To Yes'
'Most Likely'
'As I See It, Yes'
'Ask Again Later'
'Concentrate And Ask Again'
'HAHAH No..'
'Ask Again'
'Have Faith In Yourself'
'Very Doubtful'
'Outlook Not So Good'
'My Sources Say No'
'Unknown At This Time'
'Could Happen Any Moment Now'
'Is That A Joke?'
'Unlikely' )
shuffle
function sayhello(){
local n=${array[#]}-""
#display it
kdialog --msgbox "This Is What I See: ${array}"
#--clear --msgbox "${array}" 8 41
}
# show an inputbox
kdialog --title "Welcome " \
--inputbox "Ask and you shall recieve great fortune: " #8 60
function think_tank(){
progress=$(kdialog --progressbar "hmmm Let Me Think..." 4);
sleep 1;
qdbus $progress Set "" value 1 > /dev/null;
sleep 1;
qdbus $progress Set "" value 2 > /dev/null;
sleep 1;
qdbus $progress Set "" value 3 > /dev/null;
sleep 1;
qdbus $progress Set "" value 4 > /dev/null;
sleep 1;
qdbus $progress close > /dev/null;
sleep 1
#kdialog --title "This is a passive popup" --passivepopup \
#"It will disappear in about 10 seconds" 10
}
# get response
response=$?
# get data stored in $OUPUT using input redirection
name=$(<$OUTPUT)
case $response in
0)
think_tank
sayhello ${array[#]}
;;
1)
echo "Goodbye For Now."
exit 0
;;
255)
echo "Goodbye For Now."
exit 0
;;
esac
#rm $OUTPUT
done
done
After some sleep I easily figured this issue out. I removed the case statement and used if statements instead. The program would not break out of the case statement due to a return 0 from kdialog's --msgbox.
#made some quick msgbox functions
if [ "$?" = 0 ];
then
think_tank #progress bar
msg_box #results
elif [ "$?" = 1 ];
then
goodbye #closing message box
exit 0;
else
error #error message box
exit 0;
fi;
I am trying to parse arguments in ksh. Can't do getopt for the same as in short options I have two/three characters. Currently I am using for loop. Its stupid but am unable to find something better.
Question: How do I set option+value as one unit in order to parse?
Also if eval set -- $option will help me then how do I use it? echo on option does not show the expected "--" at the end. Am I assuming something wrong?
I am thinking of using a variable to keep track of when an option is found but this method seems too confusing and unnecessary.
Thanks for your time and help.
Update 1:
Adding code as pointed out. Thanks to markp, Andre Gelinas and random down-voter in making this question better. Trying to execute the script as given in line 2 and 3 of code - or any other combination of short and long options passed together.
#!/bin/ksh
# bash script1.sh --one 123 --two 234 --three "some string"
# bash script1.sh -o 123 -t 234 -th "some string"
# the following creates problems for short options.
#options=$(getopt -o o:t:th: -l one:two:three: "--" "$#")
#Since the below `eval set -- "$options"` did not append "--" at the end
#eval set -- "$options"
for i in $#; do
options="$options $i"
done
options="$options --"
# TODO capture args into variables
Attempted code below TODO until now:
for i in $options; do
echo $i
done
Will be capturing the args using:
while true; do
case $1 in
--one|-o) shift; ONE=$1
;;
--two|-t) shift; TWO=$1
;;
--three|-th) shift; THREE=$1
;;
--) shift; break
;;
esac
done
Try something like this :
#!/bin/ksh
#Default value
ONE=123
TWO=456
# getopts configuration
USAGE="[-author?Andre Gelinas <andre.gelinas#foo.bar>]"
USAGE+="[-copyright?2018]"
USAGE+="[+NAME?TestGetOpts.sh]"
USAGE+="[+DESCRIPTION?Try out for GetOps]"
USAGE+="[o:one]#[one:=$ONE?First.]"
USAGE+="[s:second]#[second:=$TWO?Second.]"
USAGE+="[t:three]:[three?Third.]"
USAGE+=$'[+SEE ALSO?\aman\a(1), \aGetOpts\a(1)]'
while getopts "$USAGE" optchar ; do
case $optchar in
o) ONE=$OPTARG ;;
s) TWO=$OPTARG ;;
t) THREE=$OPTARG ;;
esac
done
print "ONE = "$ONE
print "TWO = "$TWO
print "THREE = "$THREE
You can use either --one or -o. Using --man or --help are also working. Also -o and -s are numeric only, but -t will take anything. Hope this help.
I'm trying to trim only the left half of a string that is given to ltrim() as an argument. This is my current code.
ltrim()
{
string=${1}
divider=$((${#string} / 2))
trimrule=${2}
string_left=${string:0:$divider}
string_right=${string:$divider}
echo ${string:$divider} ## My own quick debug lines
echo ${string:0:$divider} ## My own quick debug lines
if [ $# -ne 2 ]
then
printf "%d argument(s) entered. 2 required.\n" "$#"
else
while :
do
case $string_left in
${2}*) string_left=${string_left#?} ;;
*${2}) string_left=${string_left%?} ;;
*) break ;;
esac
done
printf "Left side string is %s\n" "${string_left}"
fi
}
However, when I enter ltrim abcdefghijklmnopq abc the shell returns the following:
ijklmnopq
abcdefgh
Left side string is bcdefgh
So I only lost 'a' out of the word while I'm looking to get 'defgh' as a result. What am I doing wrong?
function substr_remove() {
echo "${1//$2/}"
}
substr_remove carfoobar123foo456 foo
Output:
carbar123456
Are you searching for something like this?
function ltrim() {
echo ${1##$2}
}
ltrim abcdefghijklmnopq abc # Prints: defghijklmnopq
Having bash, created simple scripts for accessing array element by it's index.It as follows
#! /bin/bash
OK_INDEX=0
CANCEL_INDEX=1
ERROR_INDEX=2
CONFIRM_INDEX=3
SAVE_INDEX=4
EXIT_INDEX=5
declare -a messageList=("ok"
"cancel"
"error"
"confirm"
"save"
"exit")
printf "%s \n" ${messageList[$CANCEL_INDEX]}
from above scripts i need to declare proper index variable to retrieve valid message from array list but it likely not handy for me to declare each variable and give index to them.It is nice if variable autometically getting value as like in C for ENUM data type
in C it's possible by like
enum index { OK_INDEX, CANCEL_INDEX, ERROR_INDEX,CONFIRM_INDEX,SAVE_INDEX,EXIT_INDEX};
is there any alternative for ENUM in bash?
I found lot but not succeded then have try some trick to achieve this it is as follows
ENUM=(OK_INDEX CANCEL_INDEX ERROR_INDEX CONFIRM_INDEX SAVE_INDEX EXIT_INDEX)
maxArg=${#ENUM[#]}
for ((i=0; i < $maxArg; i++)); do
name=${ENUM[i]}
declare -r ${name}=$i
done
So form above code snippet i successfully created constant but it seems lengthy means just declaring variable i need to write 5-10 lines code which is not fair.
So any one have another solution?
Try the following fragment of code ... I guess that it is what you want
#!/bin/bash
set -u
DEBUG=1
# This funcion allow to declare enum "types", I guess
enum ()
{
# skip index ???
shift
AA=${###*\{} # get string strip after {
AA=${AA%\}*} # get string strip before }
AA=${AA//,/} # delete commaa
((DEBUG)) && echo $AA
local I=0
for A in $AA ; do
eval "$A=$I"
((I++))
done
}
### Main program
# Just declare enum as you need
enum index { OK_INDEX, CANCEL_INDEX, ERROR_INDEX, CONFIRM_INDEX, SAVE_INDEX, EXIT_INDEX };
# Print value of enumerated items
echo $OK_INDEX
echo $CANCEL_INDEX
echo $ERROR_INDEX
echo $CONFIRM_INDEX
echo $SAVE_INDEX
echo $EXIT_INDEX
# Use enumerated index in program
I=CONFIRM_INDEX
case $I in
OK_INDEX )
echo "Process here when index is $I"
;;
CANCEL_INDEX )
echo "Process here when index is $I"
;;
ERROR_INDEX )
echo "Process here when index is $I"
;;
CONFIRM_INDEX )
echo "Process here when index is $I"
;;
SAVE_INDEX )
echo "Process here when index is $I"
;;
EXIT_INDEX )
echo "Process here when index is $I"
;;
esac
exit 0
My take on this:
function \
_enum()
{
## void
## (
## _IN $# : [ array<string> ] list
## )
local list=("$#")
local len=${#list[#]}
for (( i=0; i < $len; i++ )); do
eval "${list[i]}=$i"
done
}
Example:
ENUM=(
OK_INDEX
CANCEL_INDEX
ERROR_INDEX
CONFIRM_INDEX
SAVE_INDEX
EXIT_INDEX
) && _enum "${ENUM[#]}"
echo "OK_INDEX = "$OK_INDEX
echo "CANCEL_INDEX = "$CANCEL_INDEX
echo "ERROR_INDEX = "$ERROR_INDEX
echo "CONFIRM_INDEX = "$CONFIRM_INDEX
echo "SAVE_INDEX = "$SAVE_INDEX
echo "EXIT_INDEX = "$EXIT_INDEX
Output
OK_INDEX = 0
CANCEL_INDEX = 1
ERROR_INDEX = 2
CONFIRM_INDEX = 3
SAVE_INDEX = 4
EXIT_INDEX = 5
I find this to be the cleanest and most straightforward approach.
Another solution is to assign values to an associative array to make an enum set with the variable name as the prefix. This allows introspection of the enum by walking through all available values and their associated key names:
function \
_enum_set()
{
## void
## (
## _IN $1 : [ string ] prefix
## _IN ... : [ array<string> ] list
## )
local prefix=$1
local list=("$#")
local len=${#list[#]}
declare -g -A $prefix
for (( i=0; i < $len; i++ )); do
# Skip the first argument
[[ $i = 0 ]] &&
continue
eval "$prefix[${list[$i]}]=$(( $i - 1 ))"
done
}
Example (looping):
ENUM=(
OK
CANCEL
ERROR
CONFIRM
SAVE
EXIT
) && _enum_set ENUM_INDEX "${ENUM[#]}"
echo ""
for i in "${!ENUM_INDEX[#]}"; do
echo "ENUM_INDEX[$i] = "${ENUM_INDEX[$i]}
done
Output:
ENUM_INDEX[CONFIRM] = 3
ENUM_INDEX[OK] = 0
ENUM_INDEX[EXIT] = 5
ENUM_INDEX[ERROR] = 2
ENUM_INDEX[SAVE] = 4
ENUM_INDEX[CANCEL] = 1
Example (explicit):
ENUM=(
OK
CANCEL
ERROR
CONFIRM
SAVE
EXIT
) && _enum_set ENUM_INDEX "${ENUM[#]}"
echo "ENUM_INDEX[OK] = "${ENUM_INDEX[OK]}
echo "ENUM_INDEX[CANCEL] = "${ENUM_INDEX[CANCEL]}
echo "ENUM_INDEX[ERROR] = "${ENUM_INDEX[ERROR]}
echo "ENUM_INDEX[CONFIRM] = "${ENUM_INDEX[CONFIRM]}
echo "ENUM_INDEX[SAVE] = "${ENUM_INDEX[SAVE]}
echo "ENUM_INDEX[EXIT] = "${ENUM_INDEX[EXIT]}
Output:
ENUM_INDEX[OK] = 0
ENUM_INDEX[CANCEL] = 1
ENUM_INDEX[ERROR] = 2
ENUM_INDEX[CONFIRM] = 3
ENUM_INDEX[SAVE] = 4
ENUM_INDEX[EXIT] = 5
Note that associative arrays have no defined order but can always be sorted at a later point.
You can consolidate some of the lines:
$ for i in \
E_OK E_CANCEL E_ERROR E_CONFIRM E_SAVE E_EXIT; do \
readonly ${i}=$((x++)); done
$ for i in ${!E_#}; do echo $i=${!i}; done
Another version using mapfile callback function:
#!/bin/bash
mapfile -t -c 1 -C 'f(){ readonly $2=$1; }; f' << \
EOF
E_OK
E_CANCEL
E_ERROR
E_CONFIRM
E_SAVE
E_EXIT
EOF
for i in ${!E_#}; do echo $i=${!i}; done
Output:
E_CANCEL=1
E_CONFIRM=3
E_ERROR=2
E_EXIT=5
E_OK=0
E_SAVE=4
The typical workaround when an enum is wanted is to use normal strings. In these cases I even omit the otherwise mandatory quotes around variable evaluation:
state=IDLE
...
while [ $state = IDLE ]
do
...
if condition
then
state=BUSY
fi
...
if condition2
then
state=ERROR
fi
...
done
if [ $state = ERROR ]
then
...
fi
This way, of course, you have just the basic functionality of named states and neither of the following typically associated features of enums:
declaration of all possible values (self-documenting code)
associated number for each value (matter of taste if this is a feature or a wart)
no prevention/detection of mistypings (but this is rare in scripts anyway)