Bash exec in infinite while loop doesn't work - bash

#!/bin/bash
while :
do
echo twerkin
exec free -h > /ver/www/raspberry/load.txt
exec /opt/vc/bin/vcgencmd measure_temp > /var/www/raspberry/heat.txt
done
This is what I made, I am going to read it on my website, but thats not the problem. The problem is that it gives me this error:
pi#raspberrypi ~ $ sh showinfo.sh
showinfo.sh: 7: showinfo.sh: Syntax error: "done" unexpected (expecting "do")
I'm running this on my raspberry pi with Raspbian (Debian Wheezy)

You don't seem to understand what the exec keyword does. It replaces your current script (basically, thewhile loop) with the free command.
To run a command, simply specify it.
#!/bin/bash
while : ; do
free -h
/opt/vc/bin/vcgencmd measure_temp
done
(I omitted the redirections because you were overwriting the old results on each iteration. What do you actually want?)

try to change few things in your script
#!/bin/bash
while : ;
do
echo twerkin
#### commands to execute are not need to be prefixed with exec
#### + concatenate output with >>
free -h >> /ver/www/raspberry/load.txt
#### same here
/opt/vc/bin/vcgencmd measure_temp >> /var/www/raspberry/heat.txt
#### you probably would want to add a delay here, because in other way
#### the script will be executed probably way too fast
# sleep 0.01
done

Related

how to run bash script interactively from url? [duplicate]

I have a simple Bash script that takes in inputs and prints a few lines out with that inputs
fortinetTest.sh
read -p "Enter SSC IP: $ip " ip && ip=${ip:-1.1.1.1}
printf "\n"
#check IP validation
if [[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "SSC IP: $ip"
printf "\n"
else
echo "Enter a valid SSC IP address. Ex. 1.1.1.1"
exit
fi
I tried to upload them into my server, then try to run it via curl
I am not sure why the input prompt never kick in when I use cURL/wget.
Am I missing anything?
With the curl ... | bash form, bash's stdin is reading the script, so stdin is not available for the read command.
Try using a Process Substitution to invoke the remote script like a local file:
bash <( curl -s ... )
Your issue can be simply be reproduced by run the script like below
$ cat test.sh | bash
Enter a valid SSC IP address. Ex. 1.1.1.1
This is because the bash you launch with a pipe is not getting a TTY, when you do a read -p it is read from stdin which is content of the test.sh in this case. So the issue is not with curl. The issue is not reading from the tty
So the fix is to make sure you ready it from tty
read < /dev/tty -p "Enter SSC IP: $ip " ip && ip=${ip:-1.1.1.1}
printf "\n"
#check IP validation
if [[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "SSC IP: $ip"
printf "\n"
else
echo "Enter a valid SSC IP address. Ex. 1.1.1.1"
exit
fi
Once you do that even curl will start working
vagrant#vagrant:/var/www/html$ curl -s localhost/test.sh | bash
Enter SSC IP: 2.2.2.2
SSC IP: 2.2.2.2
I personally prefer source <(curl -s localhost/test.sh) option. While it is similar to bash ..., the one significant difference is how processes handled.
bash will result in a new process being spun up, and that process will evoke commands from the script.
source on the other hand will use current process to evoke commands from the script.
In some cases that can play a key role. I admit that is not very often though.
To demonstrate do the following:
### Open Two Terminals
# In the first terminal run:
echo "sleep 5" > ./myTest.sh
bash ./myTest.sh
# Switch to the second terminal and run:
ps -efjh
## Repeat the same with _source_ command
# In the first terminal run:
source ./myTest.sh
# Switch to the second terminal and run:
ps -efjh
Results should look similar to this:
Before execution:
Running bash (main + two subprocesses):
Running source (main + one subprocess):
UPDATE:
Difference in use variable usage by bash and source:
source command will use your current environment. Meaning that upon execution all changes and variable declarations, made by the script, will be available in your prompt.
bash on the other hand will be running in as a different process; therefore, all variables will be discarded when process exits.
I think everyone will agree that there are benefits and drawbacks to each method. You just have to decide which one is better for your use case.
## Test for variables declared by the script:
echo "test_var3='Some Other Value'" > ./myTest3.sh
bash ./myTest3.sh
echo $test_var3
source ./myTest3.sh
echo $test_var3
## Test for usability of current environment variables:
test_var="Some Value" # Setting a variable
echo "echo $test_var" > myTest2.sh # Creating a test script
chmod +x ./myTest2.sh # Adding execute permission
## Executing:
. myTest2.sh
bash ./myTest2.sh
source ./myTest2.sh
./myTest2.sh
## All of the above results should print the variable.
I hope this helps.

Redirect copy of stdin to file from within bash script itself

In reference to https://stackoverflow.com/a/11886837/1996022 (also shamelessly stole the title) where the question is how to capture the script's output I would like to know how I can additionally capture the scripts input. Mainly so scripts that also have user input produce complete logs.
I tried things like
exec 3< <(tee -ia foo.log <&3)
exec <&3 <(tee -ia foo.log <&3)
But nothing seems to work. I'm probably just missing something.
Maybe it'd be easier to use the script command? You could either have your users run the script with script directly, or do something kind of funky like this:
#!/bin/bash
main() {
read -r -p "Input string: "
echo "User input: $REPLY"
}
if [ "$1" = "--log" ]; then
# If the first argument is "--log", shift the arg
# out and run main
shift
main "$#"
else
# If run without log, re-run this script within a
# script command so all script I/O is logged
script -q -c "$0 --log $*" test.log
fi
Unfortunately, you can't pass a function to script -c which is why the double-call is necessary in this method.
If it's acceptable to have two scripts, you could also have a user-facing script that just calls the non-user-facing script with script:
script_for_users.sh
--------------------
#!/bin/sh
script -q -c "/path/to/real_script.sh" <log path>
real_script.sh
---------------
#!/bin/sh
<Normal business logic>
It's simpler:
#! /bin/bash
tee ~/log | your_script
The wonderful thing is your_script can be a function, command or a {} command block!

Bash command substitution freeze

Currently I encountered the following situation when bash script freeze on
PID=`cat test.pid`
After the analysis it was found that even this commands freeze
TEST=$(echo 1)
TEST=`echo 1`
Using set -x in bash script, I can see the following output
+ echo 1
1
++ echo 1
for script
#!/bin/bash
set -x
echo 1
TEST=$(echo 1)
set +x
This script is called from Qt process and everything have worked lately.
When I call this script manually from bash it also works, but when I do it from process it fails.
Currently I'm looking for possible reasons of such freezes, and I've no more ideas.
When I printed environments they matched, but I also can't prinenv inside `` as it freezes also.

How can I prevent bash from reporting an error when attempting to call a non-existing script?

I am writing a simple script in bash to check whether or not a bunch of dependencies are installed on the current system. My script attempts to run a sample script with the -h flag, greps the output for a keyword i would expected to be returned by the sample scripts, and therefore knows whether or not the sample script is installed on the system.
I then pass this through a conditional statement that basically says sample scripts = OK or sample scripts = FAIL. However, in the case in which the sample script isn't installed on the system, bash throws the warning -bash: sample_script: command not found. How can I prevent this from displaying? I tried using the 1>&2 error redirection, but the warning still appears on the screen (I want the OK/FAIL output text to be displayed on the user's screen upon running my script).
Thanks for any suggestions!
If you just want to suppress errors (stderr) and let the "OK" or "FAIL" you are echoing (stdout) pass through, you would do:
./yourscript.sh 2> /dev/null
Although the better approach would be to test whether sample_script is executable before trying to execute it. For instance:
if [ -x "$script" ]; then
*do whatever generates FAIL or OK*
fi
#devnull dixit
command -h 2>/dev/null
I use this function to be independent of which, whence, type -p and whatnot:
pathto () {
DIRLIST=$(echo "$PATH"|tr : ' ')
for e in "$#"; do
for d in $DIRLIST; do
test -f "$d/$e" -a -x "$d/$e" && echo "$d/$e"
done
done
}
pathto script will echo the full path if it can be found (and is executable). Returning 0 or 1 instead left as an exercise :-)
for bash:
if ! type -P sample_script &> /dev/null; then
echo Error: sample_script is not installed. Come back later. >&2
exit 1
fi
sample_script "$#"

shell script comparing two variables

I have created a script for updating some ipaddress in iptables. Hereby I'm describing the issues which I'm facing with that.
Issues:
Comparison not happening between two variables within a script
At the end of script i need to execute a command ie; service restart/stop etc and output of the commands should be visible while executing the script.
1) Here am comparing two variable strings:
BASE=172.31.0.0
CMD=172.31.1.0
if [[ "$CMD" == "$BASE" ]]; then
echo "ip are same"
else
echo "not matched"
fi
but there is no response/output while executing the above script. Here its not comparison is not happening..Kindly suggest a best solution to resolve this issue.
2) after executing the script I need to restart the iptables:
BASE=172.31.0.0
CMD=172.31.1.0
if [[ "$CMD" == "$BASE" ]]; then
echo "ip are same"
else
echo "not matched"
fi
service iptables restart
iptables -nvL
A script should display the output of the last two lines (commands). Kindly suggest me the best solution and how to do this in a best way.
That's very odd. This should work, so if it's not working you forgot to mention something important.
How is this script being executed? Do you simply type ./script or is it executed by some service (like cron)?
Here are some of suggestions to debug:
Sanity check: see if bash works (perhaps your login shell isn't bash, so you didn't notice). Run this at the terminal:
/bin/bash -c 'echo hello world'
It prints hello world, right? How about this:
/bin/bash -c 'BASE=172.31.0.0; CMD=172.31.1.0; if [[ "$CMD" == "$BASE" ]]; then echo "ip are same"; else echo "not matched"; fi'
If any of the above doesn't work, you have a problem with your bash installation.
Instead of executing your script with ./script.sh, run it like this:
/bin/bash script.sh
Nothing? Run this:
file script.sh
If it ends with something like "with CRLF line terminators", then cdarke nailed it: the file was created on Windows with an improper tool. Recreate it on Linux or use dos2unix. But anyway, I doubt it because with a CRLF-ending file I get this printed:
bash: ./script.sh: /bin/bash^M: bad interpreter: No such file or directory
Instead of nothing at all.
Put those this line on the beginning of the file:
set -x
(below #!/bin/bash, if you have it). This ensures a debugging trace will be printed, showing each command as it is executed.
If still there is nothing shown.. put this at your script (below set -x if you put it):
touch /tmp/hi-this-is-strange
Then check if there is a /tmp/hi-this-is-strange file after you run the script.

Resources