How to recover when stuck by executing wrong shell commands? - linux

I'm using Git Bash 2.9.0-64-bit in win7 64bit.
Here is my shell code
function sum1_x(){
a=$1
while [ $a -ge 1 ]; do
sum=$[$sum + $a]
a=$[$a - 1]
done
echo $sum
}
sum $1
In Git Bash,my type history is as follows:
wen#PC-WEN MINGW64 /d/git/ (dev)
$sh sum1_x.sh
exit
:q
quit
quit()
exit()
After I typed sh sum1_x.sh,I can no longer execute any shell command.I tried many commands as shows.I know there are bugs in my script,but how can I get back to execute shell script facing this kind of problems? Nothing can I do now.

You have several problems with your script:
you have function sum1_x but you are calling sum $1
You didn't check that input value exists, because of it you stuck in infinite loop
Here is the corrected script with check that input argument is exists:
function sum1_x(){
a=$1
while [ $a -ge 1 ]; do
sum=$[$sum + $a]
a=$[$a - 1]
done
echo $sum
}
if [ -z "$1" ]; then # check that input parameter is exists
echo "No input"
else
sum1_x $1
fi
How to stop program:
Ctrl + 'c'
Open new mingw and find pid of the progrman via ps -aux | grep "sum1_x.sh"
and then use kill pid to kill the program

As shows in the question,the shell script contains many bugs.The command sh sum1_x.sh was wrong too.It should be replaced by command sh sum1_x.sh 9 or things like it.After I fixed these bugs,it runs without problems and print the right sum.
But I still didn't know how to shop the shell script.Fortunately,By accident,I clicked Ctrl & c,and I can input shell commands again.

Related

Script to check if vim is open or another script is running?

I'm making a background script that requires a user to input a certain string (a function) to continue. The script runs fine, but will interrupt anything else that is open in vim or any script that is running. Is there a way I can test in my script if the command line is waiting for input to avoid interrupting something?
I'm running the script enclosed in parenthesis to hide the job completion message, so I'm using (. nightFall &)
Here is the script so far:
#!/bin/bash
# nightFall
clear
text=""
echo "Night begins to fall... Now might be a good time to rest."
while [[ "$text" != "rest" ]]
do
read -p "" text
done
Thank you in advance!
If you launch nightFall from the shell you are monitoring, you can use "ps" with the parent PID to see how many processes are launched by the shell as well:
# bg.sh
for k in `seq 1 15`; do
N=$(ps -ef | grep -sw $PPID | grep -v $$ | wc -l)
(( N -= 2 ))
[ "$N" -eq 0 ] && echo "At prompt"
[ "$N" -ne 0 ] && echo "Child processes: $N"
sleep 1
done
Note that I subtract 2 from N: one for the shell process itself and one for the bg.sh script. The remainder is = how many other child processes does the shell have.
Launch the above script from a shell in background:
bash bg.sh &
Then start any command (for example "sleep 15") and it will detect if you are at the prompt or in a command.

Arrays in Shell Script, not Bash

I am probably just having a brain fart, but I can not for the life of me figure out how to loop through an array in shell script, not bash. Im sure the answer is on stackoverflow somewhere already, but I can not find a method of doing so without using bash. For my embedded target system bash is not currently an option. Here is an example of what I am attempting to do and the error that is returned.
#!/bin/sh
enable0=1
enable1=1
port=0
while [ ${port} -lt 2 ]; do
if [ ${enable${port}} -eq 1 ]
then
# do some stuff
fi
port=$((port + 1))
done
Whenever I run this script the error "Bad substitution" is returned for line with the if statement. If you guys have any ideas I would greatly appreciate it. Thanks!
a="abc 123 def"
set -- $a
while [ -n "$1" ]; do
echo $1
shift
done
Output via busybox 1.27.2 ash:
abc
123
def
BusyBox provides ash which does not directly provide array support. You could use eval and something like,
#!/bin/busybox sh
enable0=0
enable1=1
for index in 0 1 ; do
eval assign="\$enable$index"
if [ $assign == 1 ]; then
echo "enable$index is enabled"
else
echo "enable$index is disabled"
fi
done
One could use positional parameters for that...
http://pubs.opengroup.org/onlinepubs/009696799/utilities/set.html
#!/bin/sh
enable0=0
enable1=1
set -- $enable0 $enable1
for index in 0 1; do
[ "$1" -eq 1 ] && echo "$1 is enabled." || echo "$1 is disabled."
shift
done
Running on busybox:
~ $ ./test.sh
0 is disabled.
1 is enabled.
It's best not to use eval unless there is no other alternative. (The recent spate of bash exploits is due to the shell internally evaling the contents of environment variables without verifying their contents first). In this case, you seem to be in complete control for the variables involved, but you can iterate over the variable values without using eval.
#!/bin/sh
enable0=1
enable1=1
for port_enabled in "$enable0" "$enable1"; do
if [ "$port_enabled" -eq 1 ]; then
# do some stuff
fi
done

Changing shell inside a shell script

in the default shell
the for loop given below
for ((i=$llimit; i<=$ulimit; i++));
do
echo $i
done;
it throws error "'((' is not expected"
but when switching to the bash shell
the for loop works fine
is there a way to change shell inside a shellscript
or any other solution as this for loop is inside a shell script
EDIT:
this is hte shell script
#!/bin/bash
nav_var=`sqlplus -s tcs384160/tcs#1234 <<\EOF
set pagesize 0 feedback off verify off heading off echo off
select max(sequence#) from v$archived_log where applied='YES' and thread#=2 and dest_id=2;
exit;
EOF`
echo $nav_var;
ulimit=`expr $nav_var - 30`;
llimit=`expr $ulimit - 200`;
for ((i=$llimit; i<=$ulimit; i++));
do ls -l arch_aceprod_2_${i}_743034701.arc;
done;
The C-style for loop you've used is a bashism.
Change the line
for ((i=$llimit; i<=$ulimit; i++));
to
for i in $(seq $llimit $ulimit);
and it would work well with both sh and bash.
EDIT: If you don't have seq, you could change the loop as:
i=$llimit
while [ $i -le $ulimit ]; do
echo "Do something here"
let i=i+1
done
By "default shell" I assume you mean /bin/sh? Is there a line starting "#!" at the top of the script?
Bash is pretty much backwards compatible with sh. If you put "#!/bin/bash" (without the quotes) as the first line this should get the whole thing to run under bash.
try another for loop syntax
for counter in {$llimit..$ulimit}
do
your logic
done
this works for all type of shells.
Or #!bin/bash will also work in your case

Re-installing Linux O.S. and then running bunch of commands in a .sh script , how to stop the script if something fails?

If i copy and paste all the commands into the terminal..
some do not even go through.
so the solution is perhaps to turn the file into an executable file
and then execute it.
but what if some commands fail.
the script keeps on executing the other commands.
obviously there is no solution to this right ?
The easiest way to do this is to use the -e option in your shell. For example:
#!/bin/sh -e
command1
command2
In this script, if command1 fails, then the script as a whole will fail at that point without running any further commands.
You can check the error code from commands you run
#!/bin/bash
function test {
"$#"
status=$?
if [ $status -ne 0 ]; then
echo "error with $1"
exit 255
fi
return $status
}
test ls
test ps -ef
test not_a_command
taken from here for more information Checking Bash exit status of several commands efficiently
#Terminal, you were almost there.
If you just stick && on the end of each command, then execution will stop with the first failure (ie. the first command that returns a non-zero exit code).
Example:
#!/bin/sh
true &&
echo 'got here' &&
echo 'got here too' &&
false &&
echo 'also got here'
produces the output
got here
got here too
(Actually, I thought it would also require line-continuation markers too: && \, but a quick test showed otherwise.)
Note: All of the above assumes that your shell is bash; I can't speak for other shells.

How to run bash script when a program open in liunx

Is there a way to execute bash script when I click a program like NetBeans or DropBox on Ubuntu
and execute a bash script when exit it
My idea create bash script on cronjob #reboot check every second if the program exist in the current processes
#!/bin/bash
NameOfprogram="NetBeans"
while [[ true ]]; do
countOfprocess=$(ps -ef |grep $NameOfprogram | wc -l)
if [[ $countOfprocess -gt 1 ]]; then
#execute bash
fi
sleep 1
done
But I think this idea not the best ,Is there a better way to achieve it?
A better approach is to wrap the executable in a script. That means you put a script with the name of the program in your path (probably $HOME/bin) and Linux will use that instead of the real executable.
Now you can execute the real program using:
/usr/bin/NetBeans "$#"
So to execute the real executable, you just put the absolute path in front of the name. The odd "$#" too pass on any arguments someone might have given the script.
Put a loop around this:
while [[ true ]]; do
/usr/bin/NetBeans "$#"
done
But there is a problem: You can't exit this program anymore. As soon as you try, it restarts. So if you just want a restart when it crashes:
while [[ true ]]; do
/usr/bin/NetBeans "$#" && exit 0
done
As long as the program exits because of an error, it will be restarted. If you quit it, the script will stop.

Resources