February 9, 201412 yr I have two ip's in a variable. pingIPs="192.168.178.150 192.168.178.153" my loop starts with: for i in "${pingIPs}" Something is wrong with the loop. I suppose the variable is not resolved into 2 strings so that there is no valid ip in the next steps. How is the loop supposed to look like? I also tried for i in "$pingIPs" Doesn't work either. Thank you for your help.
February 9, 201412 yr remove the quotes for i in ${pingIPs};do echo $i;done so it "sees" multiple values to loop over, quoting it makes it into a single string
February 9, 201412 yr Author Ahh...finally. I copied the solution with quotes somewhere from a forum... But without it works now. Thank you!
February 11, 201412 yr And here's some food for thought example using BASH arrays, here documents and manual assignments. #!/bin/bash typeset -ax LINES while read LINE do [ -z "${LINE%\#*}" ] && continue LINES=("${LINES[@]}" "${LINE}" ) # Append element to array done <<-EOF 192.168.1.1 192.168.1.2 192.168.1.3 # comment ignored # 192.168.1.99 EOF echo "array assigned from here document" set | grep LINES echo "array assigned manually" LINES[4]="192.168.1.4" LINES[5]="192.168.1.5" set | grep LINES for IP in ${LINES[@]} do echo ping ${IP} done here's the respective output array assigned from here document LINES=([0]="192.168.1.1" [1]="192.168.1.2" [2]="192.168.1.3") array assigned manually LINES=([0]="192.168.1.1" [1]="192.168.1.2" [2]="192.168.1.3" [4]="192.168.1.4" [5]="192.168.1.5") ping 192.168.1.1 ping 192.168.1.2 ping 192.168.1.3 ping 192.168.1.4 ping 192.168.1.5
February 12, 201412 yr Author "You can't teach an old dog new tricks." I had some basic programming lessons during my studies in Turbo Pascal, C and html, but that's literally the "tip of the iceberg". I never got that deep into scripting and then they launched Windows95 and took the last bit of motivation away from me. Although I'm really willing to learn those things, It's very, very time consuming. A full time job, 2 kids and some additional real life activities don't leave much room... Considering how often I will need the knowledge in the event, I must regrettably admit that "it's not worth it". Like every other language, without practice and/or regular use it's meaningless to learn. And while speaking a language is forgiving "typos", coding is not - that keeps the learning curve pretty flat. So, the only thing that remains for me to do is to ask silly questions and be patient... Forums are a blessing imho.
February 12, 201412 yr "...And while speaking a language is forgiving "typos", coding is not - that keeps the learning curve pretty flat... Forums are a blessing imho. [me=DaleWilliams]leaps to his feet, cheers, and gives a standing ovation![/me]
March 3, 201412 yr Author Opening up this once again...I'm stuck in the mud. I wanted to do some improvements on this script but after rewriting I can't get it working again. I wasted an hour yesterday night and still don't see the problem - it's really f****** disappointing! So far these are the bugs: ./auto_s3_sleep.sh: line 317: syntax error near unexpected token `(' ./auto_s3_sleep.sh: line 317: ` log_message "TCP activity (30 second average): $TCPact"' I don't know why it's not working anymore! The line of code is exactly the same as in the working script but now it throws this error... When I remove the brackets it's running further to this error. root@tower:/boot# auto_s3_sleep.sh ./auto_s3_sleep.sh: line 384: unexpected EOF while looking for matching `"' ./auto_s3_sleep.sh: line 395: syntax error: unexpected end of file I compared the files with total commander. The lines are exactly the same. Although I edited with notepad+ I I fromdos'ed the file ... nope. Looks like he can't parse the hourMatch=$(echo "$noCountdownHours" | grep "$hour" | wc -l) ??? Please have a look at it! auto_s3_sleep.sh_buggy.txt auto_s3_sleep.sh_ok.txt
March 4, 201412 yr Toward the end of line 123, at the end of a long series of hyphens, there is a very strange character where there should be a quote mark. I don't know if that's the only problem.
March 4, 201412 yr Author True, that's a weird char. Funny, the parser did not complain about that... Thanks for looking into. I will check it when I'm back home.
March 5, 201412 yr Author Toward the end of line 123, at the end of a long series of hyphens, there is a very strange character where there should be a quote mark. I don't know if that's the only problem. That was the only problem. The script runs fine now but some changes don't work like intended. This expression doesn't seem to work: log_message () { if [ "$debug" -eq 2 ] then logger –t$program_name "$1" #logger "$1" fi the log entry is like this: Mar 5 21:16:43 tower logger: \226tauto_s3_sleep.sh Start checking conditions for standby... Mar 5 21:16:43 tower logger: \226tauto_s3_sleep.sh Not sleeping due to time of day. when called: log_message "Start checking conditions for standby..." Whereas this one does: .... | logger -t$program_name logs like this: Mar 5 21:16:43 tower auto_s3_sleep.sh: Renew DHCP: no Mar 5 21:16:43 tower auto_s3_sleep.sh: Force GB LAN: yes Mar 5 21:16:43 tower auto_s3_sleep.sh: ----- I'm probably calling the internal function log_message in a wrong way? Next thing is, I'm calling the script in the go file like this: /boot/auto_s3_sleep.sh | at now +45 minutes It is not starting with 45 minutes delay though...
March 5, 201412 yr I use these definitions at the top of all shell scripts. #!/bin/bash [ ${DEBUG:=0} -gt 0 ] && set -x -v B=${0##*/} # basename of program D=${0%%/$B} # dirname of program E=${B#*.} # Extension P=${B%.*} # strip off after last . character # echo "D=${D} B=${B} P=${P} E=${E}";exit then when I call logger it's with logger -t${P}[${BASHPID}] also I would suggest changing some of this code with the redundant pipes. check_hour() { echo $(date +%H) } hour=`check_hour` noCountdownHours="18 19 20 21 22 23" hourMatch=$(echo "$noCountdownHours" | grep "$hour" | wc -l) when querying hour you end up forking and running a pipe to the internal function check_hour then there is another fork and pipe to $(date +%H), so the program is run, it's output via stdout is fed to echo. which takes the command line an puts it on stdout. There's all sorts of forking and piping for no reason. doing this hour=$(date +%H) is plenty and reduces the need to echo something on stdout that already was printed on stdout. The other code complicates things and causes all sorts of process splitting for no real benefit. I have more to say, but let me save this post first.
March 5, 201412 yr See the following code snippets for ideas on simplifying the hour list check logic. #!/bin/bash check_hour() { # this is a waste of CPU resources echo $(date +%H) } check_minute() { # this is a waste of CPU resources echo $(date +%m) } funca() { echo $BASHPID } hour=`check_hour` noCountdownHours="18 19 20 21 22 23" echo $BASHPID funca check_hour_list() { HOUR=$(date +%H) for CountdownHour in ${noCountdownHours} do if [ ${HOUR} = ${CountdownHour} ] then return 0 fi done return 1 } hour=$(date +%H) # this is a waste of CPU resources hourMatch=$(echo "$noCountdownHours" | grep "$hour" | wc -l) echo $hourMatch check_hour_list if [ $? -eq 0 ] then echo "check_hour_list current hour matched" else echo "check_hour_list current hour DID NOT MATCH" fi if check_hour_list then echo "check_hour_list current hour matched" else echo "check_hour_list current hour DID NOT MATCH" fi
March 6, 201412 yr Author OK Sir! Thank you for the pointer. First of all, let me illustrate how I see our (your's and mine) skill levels in these things: You = Ph.D vs. me = primary school You = concerned about runtime, load, efficiency vs. me = happy when it runs From my questions in the former posts you probably noticed this already... Also I'm "just" building on top of something that existed - without knowing if it's good or not. At this point I'm just happy it runs somehow... Now, I would like to implement your advice but to be honest, I probably understand 50% of that code. Either you help me in understanding your script-fu by commenting more in detail or you hack it in that script on your own (which probably takes less of your time). Find attached my working edition. ...now I'm p****** off to further study your code snippets... Edit: I'm back with some questions...see comments within the code. #!/bin/bash [ ${DEBUG:=0} -gt 0 ] && set -x -v #this does exactly what (set -x -v)? #next lines look like chinese to me but I will take them as given... B=${0##*/} # basename of program D=${0%%/$B} # dirname of program E=${B#*.} # Extension P=${B%.*} # strip off after last . character # echo "D=${D} B=${B} P=${P} E=${E}";exit # when do you use this? then when I call logger it's with logger -t${P}[${BASHPID}] Clear so far, but the expression log_message "..." $.. is easier to write and looks more comprehensible (at least to my noob brain). Is there a way to enhance the log_message function to do the equivalent of your line of code? e.g. log_message () { logger -t${P}[${BASHPID}] "$1" Another shitload of noob questions - sorry: #!/bin/bash check_hour() { # this is a waste of CPU resources echo $(date +%H) } check_minute() { # this is a waste of CPU resources echo $(date +%m) } funca() { # what is the use of this function echo $BASHPID #returns PID in order to do what??? } hour=`check_hour` noCountdownHours="18 19 20 21 22 23" echo $BASHPID #what's the good of those 2 lines? funca check_hour_list() #this function can replace the hourMatch expression in the current script { HOUR=$(date +%H) for CountdownHour in ${noCountdownHours} do if [ ${HOUR} = ${CountdownHour} ] then return 0 fi done return 1 } hour=$(date +%H) # this is a waste of CPU resources hourMatch=$(echo "$noCountdownHours" | grep "$hour" | wc -l) echo $hourMatch check_hour_list if [ $? -eq 0 ] #$? refers to what variable? the return value from check_hour_list? then echo "check_hour_list current hour matched" else echo "check_hour_list current hour DID NOT MATCH" fi if check_hour_list # the necessity of this if construction is not clear to me then echo "check_hour_list current hour matched" else echo "check_hour_list current hour DID NOT MATCH" fi auto_s3_sleep.sh_working_but_ugly_logging.txt
March 6, 201412 yr OK Sir! Thank you for the pointer. First of all, let me illustrate how I see our (your's and mine) skill levels in these things: You = Ph.D vs. me = primary school You = concerned about runtime, load, efficiency vs. me = happy when it runs From my questions in the former posts you probably noticed this already... Also I'm "just" building on top of something that existed - without knowing if it's good or not.At this point I'm just happy it runs somehow... I hear ya. No Ph.D here though. This is my trade. I've been doing this since childhood. usually I'll take the quick get it to run approach when prototyping. The issue later becomes, how does it run over time when looped a million times or so. Shell is easy to get working one way or another. It's when you have to run it over and over that things get more complex. In this case, it may not matter. quick and easy bad habits tend to propagate until one day you say.. Oh no!!! #!/bin/bash [ ${DEBUG:=0} -gt 0 ] && set -x -v #this does exactly what (set -x -v)? #next lines look like chinese to me but I will take them as given... B=${0##*/} # basename of program D=${0%%/$B} # dirname of program E=${B#*.} # Extension P=${B%.*} # strip off after last . character # echo "D=${D} B=${B} P=${P} E=${E}";exit # when do you use this? While the echo is commented out, it's there in case I need to refresh myself how the program name is breaking down. I do the same thing in my C programs. Break down the program name. put it in globals so error messages are properly tagged. then when I call logger it's with logger -t${P}[${BASHPID}] Clear so far, but the expression log_message "..." $.. is easier to write and looks more comprehensible (at least to my noob brain). Is there a way to enhance the log_message function to do the equivalent of your line of code? e.g. log_message () { logger -t${P}[${BASHPID}] "$1" Yes, you got it, change the logger message inside your function so it is tagged properly in the syslog. I did not get a chance to go through the other code. In the meantime consider that every shell function can return a value in shell 0 is always success, any other number is a failure. check_hour_list() { HOUR=$(date +%H) for CountdownHour in ${noCountdownHours} do if [ ${HOUR} = ${CountdownHour} ] then return 0 fi done return 1 } So in this snippet we are running one pipe to the date command and storing it in HOUR. Then looping across each element in the countdownhour string. Looking for a match. When a match occurs return 0 which is true. otherwise fall through and return a false. This could even be condensed with. check_hour_list() { HOUR=$(date +%H) for CountdownHour in ${noCountdownHours} do [ ${HOUR} = ${CountdownHour} ] && then return 0 done return 1 } here is how you check for an explicit return code. check_hour_list if [ $? -eq 0 ] then echo "check_hour_list current hour matched" else echo "check_hour_list current hour DID NOT MATCH" fi here is how you check for an implicit return code. if check_hour_list then echo "check_hour_list current hour matched" else echo "check_hour_list current hour DID NOT MATCH" fi I learned most of what I do from this book and various texts around the internet. The New KornShell Command And Programming Language http://www.amazon.com/o/ASIN/0131827006?tag=adapas02-20 These days I would suggest an O'Reilly book on bash.
March 6, 201412 yr #!/bin/bash [ ${DEBUG:=0} -gt 0 ] && set -x -v #this does exactly what (set -x -v)? in bash and ksh set -x -v turn on an option for verbosity and tracing of your script. This particular line says, if DEBUG is not 0, assign 0 to DEBUG. the it says, if DEBUG is assigned and > 0 turn on verbose and tracing in the shell. You can use it in various ways. here's an example of doing it on the command line assigning it in the environment beforehand. DEBUG=1 ./scriptname
March 6, 201412 yr Author Thanks for taking the time! Well, based on my experience, a Ph.D probably wouldn't be capable of scripting like that. He probably would tell me a story of what's in principle is possible and talk my ear off... This is probably the most essential passage: I've been doing this since childhood. There is nothing like practice. & You can't teach an old dog new tricks. I think the debug routine which is installed right now is OK. I can adapt your variables but the different logging options are welcome. This is not done in your version. There is only one problem when I call it like this: log_message () { logger –t$program_name "$1" It will log like this: Mar 5 21:16:43 tower logger: \226tauto_s3_sleep.sh Start checking conditions for standby... Mar 5 21:16:43 tower logger: \226tauto_s3_sleep.sh Not sleeping due to time of day. This will most likely be the same with your code, don't you think? Where is the "\226t" coming from? And why can't I pass the code in lines 109 to 124 with this command? Additionally, can you elaborate on why the next line in the go file is not working? /boot/auto_s3_sleep.sh | at now +45 minutes There is no delay. The script is starting right away.
March 6, 201412 yr #!/bin/bash [ ${DEBUG:=0} -gt 0 ] && set -x -v program_name=`basename $0` log_message () { logger -t$program_name "$1" } log_message "testing" root@unRAID:/tmp# DEBUG=1 ./auto_s3_sleep.sh program_name=`basename $0` basename $0 ++ basename ./auto_s3_sleep.sh + program_name=auto_s3_sleep.sh log_message () { logger -t$program_name "$1" } log_message "testing" + log_message testing + logger -tauto_s3_sleep.sh testing root@unRAID:/tmp# tail /var/log/syslog Mar 6 10:37:23 unRAID auto_s3_sleep.sh: testing You can see from my code example, it works. You have a bad character in the line and logger is seeing it, interpreting it and escaping it. When I tried to cut and paste the logger line into vi, it complained and truncated the line.
March 6, 201412 yr Additionally, can you elaborate on why the next line in the go file is not working? /boot/auto_s3_sleep.sh | at now +45 minutes There is no delay. The script is starting right away. echo /boot/auto_s3_sleep.sh | at now +45 minutes
March 7, 201412 yr Author Much useful information here Now that you got me on the "return code - trip" I realize that I could save some variable declaration. e.g. check_LockFile () { if [ "$checkLockFile" = $yes ] then if [ -e "/tmp/nos3sleep.lock" ] then LockFile=1 else LockFile=0 fi fi I could simply use the return code. But will this work, if I want to chain the return codes of two functions? Is this recommended? If the variable is needed often it may cause more CPU load to generate the return code every time. Can I mix return code and variables? What would be the right syntax? Like this (to check both return codes)? if [[ hour_match && check_LockFile ]] then Syntax to check one return code and a variable? if [[ check_hour && "$LockFile" -eq 0 ]] then Edit: According to my findings this should be correct: (command expansion for check_hour) if [[ $(check_hour) -eq 0 && "$LockFile" -eq 0 ]] Why are you using the variables like ${P}. I looked-up and found it is used when the variable is mixed with a string. In which line do you expect the misspelling? I can't see any alien character so far. Edit: I've been thinking of this for CountdownHour in ${noCountdownHours} do [ ${hour} = ${CountdownHour} ] && then return 0 done return 1 Won't return 1 overwrite the previous expression? Will the for loop close after the done?
March 7, 201412 yr Edit: I've been thinking of this for CountdownHour in ${noCountdownHours} do [ ${hour} = ${CountdownHour} ] && then return 0 done return 1 Won't return 1 overwrite the previous expression? Will the for loop close after the done? The for loop will return 0 (exit the shell) function as soon as hour = anything in the noCOuntdownHours list. Otherwise it will fall through and return 1.
March 7, 201412 yr Why are you using the variables like ${P}. I looked-up and found it is used when the variable is mixed with a string. P=PROGRAM PETER=PIPER echo $PETER rcotrone@rgclws:~ $ echo $PETER piper rcotrone@rgclws:~ $ echo ${P}ETER PROGRAMETER It's just being very specific about what it is you want to be returned. I've been bitten by the wrong variable returned. Which do you think will be returned?
March 7, 201412 yr Much useful information here Now that you got me on the "return code - trip" I realize that I could save some variable declaration. e.g. check_LockFile () { if [ "$checkLockFile" = $yes ] then if [ -e "/tmp/nos3sleep.lock" ] then LockFile=1 else LockFile=0 fi fi I could simply use the return code. But will this work, if I want to chain the return codes of two functions? Is this recommended? If the variable is needed often it may cause more CPU load to generate the return code every time. Can I mix return code and variables? What would be the right syntax? Like this (to check both return codes)? if [[ hour_match && check_LockFile ]] then Syntax to check one return code and a variable? if [[ check_hour && "$LockFile" -eq 0 ]] then Edit: According to my findings this should be correct: (command expansion for check_hour) if [[ $(check_hour) -eq 0 && "$LockFile" -eq 0 ]] I wouldn't do command expansion like that. The process has to split via fork, a pipe occurs and then you are just using the return value anyway. The reason to use return codes instead of variables is readability and being concise when appropriate. The reason to use a variable is when you are doing many test comparisons in a loop. You can have the check_hour function set a global variable and ALSO return that via the return command. Then you can have the best of both worlds. A variable to check the last status of the call and a return code when needed. As far as proper syntax for the two shell functions, I have not explored that yet. It's worthy of a test yourself.
March 7, 201412 yr In which line do you expect the misspelling? I can't see any alien character so far. I would suggest re-typing this line from scratch. There's some weird character between logger and -t I believe. When I cut and pasted the line from notepad into a terminal session running vi, it truncated the line with an error. log_message () { logger –t$program_name "$1"
March 7, 201412 yr Author I wouldn't do command expansion like that. The process has to split via fork, a pipe occurs and then you are just using the return value anyway. The reason to use return codes instead of variables is readability and being concise when appropriate. The reason to use a variable is when you are doing many test comparisons in a loop. You can have the check_hour function set a global variable and ALSO return that via the return command. Then you can have the best of both worlds. A variable to check the last status of the call and a return code when needed. I'm sorry but you lost me with this one. Where is the fork and the pipe? Conciseness is OK if you know what you're doing. For example this: if check_hour_list then echo "check_hour_list current hour matched" else echo "check_hour_list current hour DID NOT MATCH" fi Not very clear at first sight (at least to me) because it implies many things I did not know.
March 7, 201412 yr I wouldn't do command expansion like that. The process has to split via fork, a pipe occurs and then you are just using the return value anyway. I'm sorry but you lost me with this one. Where is the fork and the pipe? Anytime you do a `command` or $(command) The process sets up a pipe, the process splits with a fork, The child does the command inside the ` ` or $(). the parent reads/processes the data, the child ends. For one or two commands it's not a big deal. When you do something in a loop over and over many many times rapidly, it adds up to allot of wasted CPU cycles.
Archived
This topic is now archived and is closed to further replies.